<commit_before>/* Copyright 2019 Axel Huebl, Benjamin Worpitz
 *
 * This file is part of Alpaka.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#pragma once

#include <alpaka/core/BoostPredef.hpp>
#include <alpaka/core/Common.hpp>
#include <alpaka/meta/Set.hpp>

#include <type_traits>
#include <cstddef>

namespace alpaka
{
    namespace meta
    {
        //#############################################################################
        // This could be replaced with c++14 std::IntegerSequence if we raise the minimum.
        template<
            typename T,
            T... Tvals>
        struct IntegerSequence
        {
            static_assert(std::is_integral<T>::value, "IntegerSequence<T, I...> requires T to be an integral type.");

            using type = IntegerSequence<T, Tvals...>;
            using value_type = T;

            ALPAKA_FN_HOST_ACC static auto size() noexcept
            -> std::size_t
            {
                return (sizeof...(Tvals));
            }
        };

        namespace detail
        {
            //#############################################################################
            template<
                typename TDstType,
                typename TIntegerSequence>
            struct ConvertIntegerSequence;
            //#############################################################################
            template<
                typename TDstType,
                typename T,
                T... Tvals>
            struct ConvertIntegerSequence<
                TDstType,
                IntegerSequence<T, Tvals...>>
            {
                using type = IntegerSequence<TDstType, static_cast<TDstType>(Tvals)...>;
            };
        }
        //#############################################################################
        template<
            typename TDstType,
            typename TIntegerSequence>
        using ConvertIntegerSequence = typename detail::ConvertIntegerSequence<TDstType, TIntegerSequence>::type;

        namespace detail
        {
            //#############################################################################
            template<bool TisSizeNegative, bool TbIsBegin, typename T, T Tbegin, typename TIntCon, typename TIntSeq>
            struct MakeIntegerSequenceHelper
            {
                static_assert(!TisSizeNegative, "MakeIntegerSequence<T, N> requires N to be non-negative.");
            };
            //#############################################################################
            template<typename T, T Tbegin, T... Tvals>
            struct MakeIntegerSequenceHelper<false, true, T, Tbegin, std::integral_constant<T, Tbegin>, IntegerSequence<T, Tvals...> >
            {
                using type = IntegerSequence<T, Tvals...>;
            };
            //#############################################################################
            template<typename T, T Tbegin, T TIdx, T... Tvals>
            struct MakeIntegerSequenceHelper<false, false, T, Tbegin, std::integral_constant<T, TIdx>, IntegerSequence<T, Tvals...> >
            {
                using type = typename MakeIntegerSequenceHelper<false, TIdx == (Tbegin+1), T, Tbegin, std::integral_constant<T, TIdx - 1>, IntegerSequence<T, TIdx - 1, Tvals...> >::type;
            };
        }

        //#############################################################################
        template<typename T, T Tbegin, T Tsize>
        using MakeIntegerSequenceOffset = typename detail::MakeIntegerSequenceHelper<(Tsize < 0), (Tsize == 0), T, Tbegin, std::integral_constant<T, Tbegin+Tsize>, IntegerSequence<T> >::type;

        //#############################################################################
        template<typename T, T Tsize>
        using MakeIntegerSequence = MakeIntegerSequenceOffset<T, 0u, Tsize>;

        //#############################################################################
        //! Checks if the integral values are unique.
        template<
            typename T,
            T... Tvals>
        struct IntegralValuesUnique
        {
            static constexpr bool value = meta::IsParameterPackSet<std::integral_constant<T, Tvals>...>::value;
        };

        //#############################################################################
        //! Checks if the values in the index sequence are unique.
        template<
            typename TIntegerSequence>
        struct IntegerSequenceValuesUnique;
        //#############################################################################
        //! Checks if the values in the index sequence are unique.
        template<
            typename T,
            T... Tvals>
        struct IntegerSequenceValuesUnique<
            std::integer_sequence<T, Tvals...>>
        {
            static constexpr bool value = IntegralValuesUnique<T, Tvals...>::value;
        };

        //#############################################################################
        //! Checks if the integral values are within the given range.
        template<
            typename T,
            T Tmin,
            T Tmax,
            T... Tvals>
        struct IntegralValuesInRange;
        //#############################################################################
        //! Checks if the integral values are within the given range.
        template<
            typename T,
            T Tmin,
            T Tmax>
        struct IntegralValuesInRange<
            T,
            Tmin,
            Tmax>
        {
            static constexpr bool value = true;
        };
        //#############################################################################
        //! Checks if the integral values are within the given range.
        template<
            typename T,
            T Tmin,
            T Tmax,
            T I,
            T... Tvals>
        struct IntegralValuesInRange<
            T,
            Tmin,
            Tmax,
            I,
            Tvals...>
        {
            static constexpr bool value = (I >= Tmin) && (I <=Tmax) && IntegralValuesInRange<T, Tmin, Tmax, Tvals...>::value;
        };

        //#############################################################################
        //! Checks if the values in the index sequence are within the given range.
        template<
            typename TIntegerSequence,
            typename T,
            T Tmin,
            T Tmax>
        struct IntegerSequenceValuesInRange;
        //#############################################################################
        //! Checks if the values in the index sequence are within the given range.
        template<
            typename T,
            T... Tvals,
            T Tmin,
            T Tmax>
        struct IntegerSequenceValuesInRange<
            std::integer_sequence<T, Tvals...>,
            T,
            Tmin,
            Tmax>
        {
            static constexpr bool value = IntegralValuesInRange<T, Tmin, Tmax, Tvals...>::value;
        };
    }
}
<commit_msg>Remove unused includes<commit_after>/* Copyright 2019 Axel Huebl, Benjamin Worpitz
 *
 * This file is part of Alpaka.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#pragma once

#include <alpaka/core/Common.hpp>
#include <alpaka/meta/Set.hpp>

#include <type_traits>
#include <utility>
#include <cstddef>

namespace alpaka
{
    namespace meta
    {
        //#############################################################################
        // This could be replaced with c++14 std::IntegerSequence if we raise the minimum.
        template<
            typename T,
            T... Tvals>
        struct IntegerSequence
        {
            static_assert(std::is_integral<T>::value, "IntegerSequence<T, I...> requires T to be an integral type.");

            using type = IntegerSequence<T, Tvals...>;
            using value_type = T;

            ALPAKA_FN_HOST_ACC static auto size() noexcept
            -> std::size_t
            {
                return (sizeof...(Tvals));
            }
        };

        namespace detail
        {
            //#############################################################################
            template<
                typename TDstType,
                typename TIntegerSequence>
            struct ConvertIntegerSequence;
            //#############################################################################
            template<
                typename TDstType,
                typename T,
                T... Tvals>
            struct ConvertIntegerSequence<
                TDstType,
                IntegerSequence<T, Tvals...>>
            {
                using type = IntegerSequence<TDstType, static_cast<TDstType>(Tvals)...>;
            };
        }
        //#############################################################################
        template<
            typename TDstType,
            typename TIntegerSequence>
        using ConvertIntegerSequence = typename detail::ConvertIntegerSequence<TDstType, TIntegerSequence>::type;

        namespace detail
        {
            //#############################################################################
            template<bool TisSizeNegative, bool TbIsBegin, typename T, T Tbegin, typename TIntCon, typename TIntSeq>
            struct MakeIntegerSequenceHelper
            {
                static_assert(!TisSizeNegative, "MakeIntegerSequence<T, N> requires N to be non-negative.");
            };
            //#############################################################################
            template<typename T, T Tbegin, T... Tvals>
            struct MakeIntegerSequenceHelper<false, true, T, Tbegin, std::integral_constant<T, Tbegin>, IntegerSequence<T, Tvals...> >
            {
                using type = IntegerSequence<T, Tvals...>;
            };
            //#############################################################################
            template<typename T, T Tbegin, T TIdx, T... Tvals>
            struct MakeIntegerSequenceHelper<false, false, T, Tbegin, std::integral_constant<T, TIdx>, IntegerSequence<T, Tvals...> >
            {
                using type = typename MakeIntegerSequenceHelper<false, TIdx == (Tbegin+1), T, Tbegin, std::integral_constant<T, TIdx - 1>, IntegerSequence<T, TIdx - 1, Tvals...> >::type;
            };
        }

        //#############################################################################
        template<typename T, T Tbegin, T Tsize>
        using MakeIntegerSequenceOffset = typename detail::MakeIntegerSequenceHelper<(Tsize < 0), (Tsize == 0), T, Tbegin, std::integral_constant<T, Tbegin+Tsize>, IntegerSequence<T> >::type;

        //#############################################################################
        template<typename T, T Tsize>
        using MakeIntegerSequence = MakeIntegerSequenceOffset<T, 0u, Tsize>;

        //#############################################################################
        //! Checks if the integral values are unique.
        template<
            typename T,
            T... Tvals>
        struct IntegralValuesUnique
        {
            static constexpr bool value = meta::IsParameterPackSet<std::integral_constant<T, Tvals>...>::value;
        };

        //#############################################################################
        //! Checks if the values in the index sequence are unique.
        template<
            typename TIntegerSequence>
        struct IntegerSequenceValuesUnique;
        //#############################################################################
        //! Checks if the values in the index sequence are unique.
        template<
            typename T,
            T... Tvals>
        struct IntegerSequenceValuesUnique<
            std::integer_sequence<T, Tvals...>>
        {
            static constexpr bool value = IntegralValuesUnique<T, Tvals...>::value;
        };

        //#############################################################################
        //! Checks if the integral values are within the given range.
        template<
            typename T,
            T Tmin,
            T Tmax,
            T... Tvals>
        struct IntegralValuesInRange;
        //#############################################################################
        //! Checks if the integral values are within the given range.
        template<
            typename T,
            T Tmin,
            T Tmax>
        struct IntegralValuesInRange<
            T,
            Tmin,
            Tmax>
        {
            static constexpr bool value = true;
        };
        //#############################################################################
        //! Checks if the integral values are within the given range.
        template<
            typename T,
            T Tmin,
            T Tmax,
            T I,
            T... Tvals>
        struct IntegralValuesInRange<
            T,
            Tmin,
            Tmax,
            I,
            Tvals...>
        {
            static constexpr bool value = (I >= Tmin) && (I <=Tmax) && IntegralValuesInRange<T, Tmin, Tmax, Tvals...>::value;
        };

        //#############################################################################
        //! Checks if the values in the index sequence are within the given range.
        template<
            typename TIntegerSequence,
            typename T,
            T Tmin,
            T Tmax>
        struct IntegerSequenceValuesInRange;
        //#############################################################################
        //! Checks if the values in the index sequence are within the given range.
        template<
            typename T,
            T... Tvals,
            T Tmin,
            T Tmax>
        struct IntegerSequenceValuesInRange<
            std::integer_sequence<T, Tvals...>,
            T,
            Tmin,
            Tmax>
        {
            static constexpr bool value = IntegralValuesInRange<T, Tmin, Tmax, Tvals...>::value;
        };
    }
}
<|endoftext|>


<commit_before>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/morphablemodel/PcaModel.hpp
 *
 * Copyright 2014-2017 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#ifndef PCAMODEL_HPP_
#define PCAMODEL_HPP_

#include "cereal/access.hpp"
#include "cereal/types/array.hpp"
#include "cereal/types/vector.hpp"
#include "eos/morphablemodel/io/eigen_cerealisation.hpp"
#include "cereal/archives/binary.hpp"

#include "Eigen/Core"

#include <array>
#include <cassert>
#include <random>
#include <string>
#include <vector>
#include <fstream>

namespace eos {
namespace morphablemodel {

// Forward declarations of free functions:
Eigen::MatrixXf rescale_pca_basis(const Eigen::MatrixXf& orthonormal_basis,
                                  const Eigen::VectorXf& eigenvalues);
Eigen::MatrixXf normalise_pca_basis(const Eigen::MatrixXf& rescaled_basis,
                                    const Eigen::VectorXf& eigenvalues);

/**
 * @brief This class represents a PCA-model that consists of:
 *   - a mean vector (y x z)
 *   - a PCA basis matrix (orthonormal and rescaled)
 *   - a PCA variance vector.
 *
 * It also contains a list of triangles to built a mesh as well as a mapping
 * from landmark points to the corresponding vertex-id in the mesh.
 */
class PcaModel
{
public:
    PcaModel() = default;

    /**
	 * Construct a PCA model from given mean, normalised PCA basis, eigenvalues
     * and triangle list.
     *
     * See the documentation of the member variables for how the data should
     * be arranged.
     *
     * @param[in] mean The mean used to build the PCA model.
     * @param[in] orthonormal_pca_basis An orthonormal PCA basis (eigenvectors).
     * @param[in] eigenvalues The eigenvalues used to build the PCA model.
     * @param[in] triangle_list An index list of how to assemble the mesh.
     */
    PcaModel(Eigen::VectorXf mean, Eigen::MatrixXf orthonormal_pca_basis, Eigen::VectorXf eigenvalues,
             std::vector<std::array<int, 3>> triangle_list)
        : mean(mean), orthonormal_pca_basis(orthonormal_pca_basis), eigenvalues(eigenvalues),
          triangle_list(triangle_list)
    {
        rescaled_pca_basis = rescale_pca_basis(orthonormal_pca_basis, eigenvalues);
    };

    /**
     * Returns the number of principal components in the model.
     *
     * @return The number of principal components in the model.
     */
    int get_num_principal_components() const
    {
        // Note: we could assert(rescaled_pca_basis.cols==orthonormal_pca_basis.cols)
        return rescaled_pca_basis.cols();
    };

    /**
     * Returns the dimension of the data, i.e. the number of shape dimensions.
     *
     * As the data is arranged in a [x y z x y z ...] fashion, dividing this by
     * three yields the number of vertices in the model.
     *
     * @return The dimension of the data.
     */
    int get_data_dimension() const
    {
        // Note: we could assert(rescaled_pca_basis.rows==orthonormal_pca_basis.rows)
        return rescaled_pca_basis.rows();
    };

    /**
     * Returns a list of triangles on how to assemble the vertices into a mesh.
     *
     * @return The list of triangles to build a mesh.
     */
    std::vector<std::array<int, 3>> get_triangle_list() const
    {
        return triangle_list;
    };

    /**
     * Returns the mean of the model.
     *
     * @return The mean of the model.
     */
    const Eigen::VectorXf& get_mean() const
    {
        return mean;
    };

    /**
     * Return the value of the mean at a given vertex index.
     *
     * @param[in] vertex_index A vertex index.
     * @return A 3-dimensional vector containing the values at the given vertex index.
     */
    Eigen::Vector3f get_mean_at_point(int vertex_index) const
    {
        vertex_index *= 3;
        // Note: We could maybe also return a const& to mean.block(...).
        return Eigen::Vector3f(mean(vertex_index), mean(vertex_index + 1), mean(vertex_index + 2));
    };

    /**
     * Draws a random sample from the model, where the coefficients are drawn
     * from a standard normal (or with the given standard deviation).
     *
     * @param[in] engine Random number engine used to draw random coefficients.
     * @param[in] sigma The standard deviation.
     * @return A random sample from the model.
     */
    template <class RNG>
    Eigen::VectorXf draw_sample(RNG& engine, float sigma = 1.0f) const
    {
        std::normal_distribution<float> distribution(0.0f, sigma); // this constructor takes the stddev

        std::vector<float> alphas(get_num_principal_components());

        for (auto&& a : alphas)
        {
            a = distribution(engine);
        }

        return draw_sample(alphas);
    };

    /**
     * Returns a sample from the model with the given PCA coefficients.
     * The given coefficients should follow a standard normal distribution, i.e.
     * not be "normalised" with their eigenvalues/variances.
     *
     * @param[in] coefficients The PCA coefficients used to generate the sample.
     * @return A model instance with given coefficients.
     */
    Eigen::VectorXf draw_sample(std::vector<float> coefficients) const
    {
        // Fill the rest with zeros if not all coefficients are given:
        if (coefficients.size() < get_num_principal_components())
        {
            coefficients.resize(get_num_principal_components());
        }
        const Eigen::Map<Eigen::VectorXf> alphas(coefficients.data(), coefficients.size());

        const Eigen::VectorXf model_sample = mean + rescaled_pca_basis * alphas;

        return model_sample;
    };

    /**
     * @copydoc PcaModel::draw_sample(std::vector<float>) const
     */
    Eigen::VectorXf draw_sample(std::vector<double> coefficients) const
    {
        // We have to convert the vector of doubles to float:
        const std::vector<float> coeffs_float(std::begin(coefficients), std::end(coefficients));
        return draw_sample(coeffs_float);
    };

    /**
     * Returns the PCA basis matrix, i.e. the eigenvectors.
     * Each column of the matrix is an eigenvector.
     * The returned basis is rescaled, i.e. every eigenvector
     * is rescaled by multiplying it with the square root of its eigenvalue.
     *
     * @return Returns the rescaled PCA basis matrix.
     */
    const Eigen::MatrixXf& get_rescaled_pca_basis() const
    {
        return rescaled_pca_basis;
    };

    /**
     * Returns the PCA basis for a particular vertex, from the rescaled basis.
     *
     * Note: The function does not return the i-th basis vector - it returns all basis
     * vectors, but only the block that is relevant for the vertex \p vertex_id.
     *
     * Todo: Can we return a const & view that points into the original data?
	 *       I think actually .block returns a const, and by not defining our function
	 *       const, we might copy the data here actually?
     *
     * @param[in] vertex_id A vertex index. Make sure it is valid.
     * @return A 1x3? 3x1? matrix that points to the rows in the original basis.
     */
    Eigen::MatrixXf get_rescaled_pca_basis_at_point(int vertex_id) const
    {
        vertex_id *= 3;                           // the basis is stored in the format [x y z x y z ...]
        assert(vertex_id < get_data_dimension()); // Make sure the given vertex index isn't larger than the
                                                  // number of model vertices.
        return rescaled_pca_basis.block(vertex_id, 0, 3, rescaled_pca_basis.cols());
    };

    /**
     * Returns the PCA basis matrix, i.e. the eigenvectors.
     * Each column of the matrix is an eigenvector.
     * The returned basis is orthonormal, i.e. the eigenvectors
     * are not scaled by their respective eigenvalues.
     *
     * @return Returns the orthonormal PCA basis matrix.
     */
    const Eigen::MatrixXf& get_orthonormal_pca_basis() const
    {
        return orthonormal_pca_basis;
    };

    /**
     * Returns the PCA basis for a particular vertex, from the orthonormal basis.
     *
     * Note: The function does not return the i-th basis vector - it returns all basis
     * vectors, but only the block that is relevant for the vertex \p vertex_id.
     *
     * @param[in] vertex_id A vertex index. Make sure it is valid.
     * @return A matrix that points to the rows in the original basis.
     */
    Eigen::MatrixXf get_orthonormal_pca_basis_at_point(int vertex_id) const
    {
        vertex_id *= 3;                           // the basis is stored in the format [x y z x y z ...]
        assert(vertex_id < get_data_dimension()); // Make sure the given vertex index isn't larger than the
                                                  // number of model vertices.
        return orthonormal_pca_basis.block(vertex_id, 0, 3, orthonormal_pca_basis.cols());
    };

    /**
     * Returns the models eigenvalues.
     *
     * @return The eigenvalues.
     */
    const Eigen::VectorXf& get_eigenvalues() const
    {
        return eigenvalues;
    };

    /**
     * Returns a specific eigenvalue.
     *
     * @param[in] index The index of the eigenvalue to return.
     * @return The eigenvalue.
     */
    float get_eigenvalue(int index) const
    {
        // no assert - Eigen checks access with an assert in debug builds
        return eigenvalues(index);
    };

private:
    Eigen::VectorXf mean; ///< A 3m x 1 col-vector (xyzxyz...)', where m is the number of model-vertices.
    Eigen::MatrixXf orthonormal_pca_basis; ///< m x n (rows x cols) = numShapeDims x numShapePcaCoeffs,
                                           ///< (=eigenvector matrix V). Each column is an eigenvector.
    Eigen::MatrixXf rescaled_pca_basis;    ///< m x n (rows x cols) = numShapeDims x numShapePcaCoeffs,
                                           ///< (=eigenvector matrix V). Each column is an eigenvector.
    Eigen::VectorXf eigenvalues;           ///< A col-vector of the eigenvalues (variances in the PCA space).

    std::vector<std::array<int, 3>> triangle_list; ///< List of triangles that make up the mesh of the model.

    friend class cereal::access;
    /**
     * Serialises this class using cereal.
     *
     * @param[in] archive The archive to serialise to (or to serialise from).
     */
    template <class Archive>
    void serialize(Archive& archive)
    {
        archive(CEREAL_NVP(mean), CEREAL_NVP(orthonormal_pca_basis), CEREAL_NVP(eigenvalues),
                CEREAL_NVP(triangle_list));
        // If we're loading, we have to recompute the rescaled basis, so that it's available (we don't
        // store it anymore):
        if (Archive::is_loading::value)
        {
            rescaled_pca_basis = rescale_pca_basis(orthonormal_pca_basis, eigenvalues);
        }
    };
};

/**
 * Helper method to load a PCA model from
 * a cereal::BinaryInputArchive from the harddisk.
 *
 * Usually, morphablemodel::load_model(std::string) should be used to directly
 * load a MorphableModel. This function can be useful when it is necessary to just
 * load a PCA model.
 *
 * @param[in] filename Filename to a model.
 * @return The loaded PCA model.
 * @throw std::runtime_error When the file given in \c filename fails to be opened (most likely because the
 * file doesn't exist).
 */
inline PcaModel load_pca_model(std::string filename)
{
    PcaModel model;

    std::ifstream file(filename, std::ios::binary);
    if (file.fail())
    {
        throw std::runtime_error("Error opening given file: " + filename);
    }
    cereal::BinaryInputArchive input_archive(file);
    input_archive(model);

    return model;
};

/**
 * Helper method to save a PCA model to the
 * harddrive as cereal::BinaryOutputArchive.
 *
 * @param[in] model The model to be saved.
 * @param[in] filename Filename for the model.
 */
inline void save_pca_model(PcaModel model, std::string filename)
{
    std::ofstream file(filename, std::ios::binary);
    cereal::BinaryOutputArchive output_archive(file);
    output_archive(model);
};

/**
 * Takes an orthonormal PCA basis matrix (a matrix consisting
 * of the eigenvectors) and rescales it, i.e. multiplies each
 * eigenvector by the square root of its corresponding
 * eigenvalue.
 *
 * @param[in] orthonormal_basis An orthonormal_basis PCA basis matrix.
 * @param[in] eigenvalues A row or column vector of eigenvalues.
 * @return The rescaled PCA basis matrix.
 */
inline Eigen::MatrixXf rescale_pca_basis(const Eigen::MatrixXf& orthonormal_basis,
                                         const Eigen::VectorXf& eigenvalues)
{
    Eigen::MatrixXf rescaled_basis(orthonormal_basis.rows(),
                                   orthonormal_basis.cols()); // empty matrix with the same dimensions
    const Eigen::VectorXf sqrt_of_eigenvalues = eigenvalues.array().sqrt();
    // Rescale the basis: We multiply each eigenvector (i.e. each column) with the square root of its
    // corresponding eigenvalue
    for (int basis = 0; basis < orthonormal_basis.cols(); ++basis)
    {
        rescaled_basis.col(basis) = orthonormal_basis.col(basis) * sqrt_of_eigenvalues(basis);
    }

    return rescaled_basis;
};

/**
 * Takes a rescaled PCA basis matrix and scales it back to
 * an orthonormal basis matrix by multiplying each eigenvector
 * by 1 over the square root of its corresponding eigenvalue.
 *
 * @param[in] rescaled_basis A rescaled PCA basis matrix.
 * @param[in] eigenvalues A row or column vector of eigenvalues.
 * @return The orthonormal PCA basis matrix.
 */
inline Eigen::MatrixXf normalise_pca_basis(const Eigen::MatrixXf& rescaled_basis,
                                           const Eigen::VectorXf& eigenvalues)
{
    Eigen::MatrixXf orthonormal_basis(rescaled_basis.rows(),
                                      rescaled_basis.cols()); // empty matrix with the same dimensions
    const Eigen::VectorXf one_over_sqrt_of_eigenvalues = eigenvalues.array().rsqrt();
    // "Normalise" the basis: We multiply each eigenvector (i.e. each column) with 1 over the square root of
    // its corresponding eigenvalue
    for (int basis = 0; basis < rescaled_basis.cols(); ++basis)
    {
        orthonormal_basis.col(basis) = rescaled_basis.col(basis) * one_over_sqrt_of_eigenvalues(basis);
    }

    return orthonormal_basis;
};

} /* namespace morphablemodel */
} /* namespace eos */

#endif /* PCAMODEL_HPP_ */
<commit_msg>Updated comments in PcaModel<commit_after>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/morphablemodel/PcaModel.hpp
 *
 * Copyright 2014-2017 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#ifndef PCAMODEL_HPP_
#define PCAMODEL_HPP_

#include "cereal/access.hpp"
#include "cereal/types/array.hpp"
#include "cereal/types/vector.hpp"
#include "eos/morphablemodel/io/eigen_cerealisation.hpp"
#include "cereal/archives/binary.hpp"

#include "Eigen/Core"

#include <array>
#include <cassert>
#include <random>
#include <string>
#include <vector>
#include <fstream>

namespace eos {
namespace morphablemodel {

// Forward declarations of free functions:
Eigen::MatrixXf rescale_pca_basis(const Eigen::MatrixXf& orthonormal_basis,
                                  const Eigen::VectorXf& eigenvalues);
Eigen::MatrixXf normalise_pca_basis(const Eigen::MatrixXf& rescaled_basis,
                                    const Eigen::VectorXf& eigenvalues);

/**
 * @brief This class represents a PCA-model that consists of:
 *   - a mean vector (y x z)
 *   - a PCA basis matrix (orthonormal and rescaled)
 *   - a PCA variance vector.
 *
 * It also contains a list of triangles to built a mesh as well as a mapping
 * from landmark points to the corresponding vertex-id in the mesh.
 */
class PcaModel
{
public:
    PcaModel() = default;

    /**
	 * Construct a PCA model from given mean, normalised PCA basis, eigenvalues
     * and triangle list.
     *
     * See the documentation of the member variables for how the data should
     * be arranged.
     *
     * @param[in] mean The mean used to build the PCA model.
     * @param[in] orthonormal_pca_basis An orthonormal PCA basis (eigenvectors).
     * @param[in] eigenvalues The eigenvalues used to build the PCA model.
     * @param[in] triangle_list An index list of how to assemble the mesh.
     */
    PcaModel(Eigen::VectorXf mean, Eigen::MatrixXf orthonormal_pca_basis, Eigen::VectorXf eigenvalues,
             std::vector<std::array<int, 3>> triangle_list)
        : mean(mean), orthonormal_pca_basis(orthonormal_pca_basis), eigenvalues(eigenvalues),
          triangle_list(triangle_list)
    {
        rescaled_pca_basis = rescale_pca_basis(orthonormal_pca_basis, eigenvalues);
    };

    /**
     * Returns the number of principal components in the model.
     *
     * @return The number of principal components in the model.
     */
    int get_num_principal_components() const
    {
        // Note: we could assert(rescaled_pca_basis.cols==orthonormal_pca_basis.cols)
        return rescaled_pca_basis.cols();
    };

    /**
     * Returns the dimension of the data, i.e. the number of shape dimensions.
     *
     * As the data is arranged in a [x y z x y z ...] fashion, dividing this by
     * three yields the number of vertices in the model.
     *
     * @return The dimension of the data.
     */
    int get_data_dimension() const
    {
        // Note: we could assert(rescaled_pca_basis.rows==orthonormal_pca_basis.rows)
        return rescaled_pca_basis.rows();
    };

    /**
     * Returns a list of triangles on how to assemble the vertices into a mesh.
     *
     * @return The list of triangles to build a mesh.
     */
    std::vector<std::array<int, 3>> get_triangle_list() const
    {
        return triangle_list;
    };

    /**
     * Returns the mean of the model.
     *
     * @return The mean of the model.
     */
    const Eigen::VectorXf& get_mean() const
    {
        return mean;
    };

    /**
     * Return the value of the mean at a given vertex index.
     *
     * @param[in] vertex_index A vertex index.
     * @return A 3-dimensional vector containing the values at the given vertex index.
     */
    Eigen::Vector3f get_mean_at_point(int vertex_index) const
    {
        vertex_index *= 3;
        // Note: We could maybe also return a const& to mean.block(...).
        return Eigen::Vector3f(mean(vertex_index), mean(vertex_index + 1), mean(vertex_index + 2));
    };

    /**
     * Draws a random sample from the model, where the coefficients are drawn
     * from a standard normal (or with the given standard deviation).
     *
     * @param[in] engine Random number engine used to draw random coefficients.
     * @param[in] sigma The standard deviation.
     * @return A random sample from the model.
     */
    template <class RNG>
    Eigen::VectorXf draw_sample(RNG& engine, float sigma = 1.0f) const
    {
        std::normal_distribution<float> distribution(0.0f, sigma); // this constructor takes the stddev

        std::vector<float> alphas(get_num_principal_components());

        for (auto&& a : alphas)
        {
            a = distribution(engine);
        }

        return draw_sample(alphas);
    };

    /**
     * Returns a sample from the model with the given PCA coefficients.
     * The given coefficients should follow a standard normal distribution, i.e.
     * not be "normalised" with their eigenvalues/variances.
     *
     * @param[in] coefficients The PCA coefficients used to generate the sample.
     * @return A model instance with given coefficients.
     */
    Eigen::VectorXf draw_sample(std::vector<float> coefficients) const
    {
        // Fill the rest with zeros if not all coefficients are given:
        if (coefficients.size() < get_num_principal_components())
        {
            coefficients.resize(get_num_principal_components());
        }
        const Eigen::Map<Eigen::VectorXf> alphas(coefficients.data(), coefficients.size());

        const Eigen::VectorXf model_sample = mean + rescaled_pca_basis * alphas;

        return model_sample;
    };

    /**
     * @copydoc PcaModel::draw_sample(std::vector<float>) const
     */
    Eigen::VectorXf draw_sample(std::vector<double> coefficients) const
    {
        // We have to convert the vector of doubles to float:
        const std::vector<float> coeffs_float(std::begin(coefficients), std::end(coefficients));
        return draw_sample(coeffs_float);
    };

    /**
     * Returns the PCA basis matrix, i.e. the eigenvectors.
     * Each column of the matrix is an eigenvector.
     * The returned basis is rescaled, i.e. every eigenvector
     * is rescaled by multiplying it with the square root of its eigenvalue.
     *
     * @return Returns the rescaled PCA basis matrix.
     */
    const Eigen::MatrixXf& get_rescaled_pca_basis() const
    {
        return rescaled_pca_basis;
    };

    /**
     * Returns the PCA basis for a particular vertex, from the rescaled basis.
     *
     * Note: The function does not return the i-th basis vector - it returns all basis
     * vectors, but only the block that is relevant for the vertex \p vertex_id.
     *
     * Todo: Can we return a const & view that points into the original data?
     *       I think it's not that easy - if we return e.g. "const auto&", then the compiler complains about
     *       returning a reference to a temporary.
     *       This will probably help: https://eigen.tuxfamily.org/dox/classEigen_1_1Block.html
     *
     * @param[in] vertex_id A vertex index. Make sure it is valid.
     * @return A 3 x num_principal_components matrix of the relevant rows of the original basis.
     */
    Eigen::MatrixXf get_rescaled_pca_basis_at_point(int vertex_id) const
    {
        vertex_id *= 3;                           // the basis is stored in the format [x y z x y z ...]
        assert(vertex_id < get_data_dimension()); // Make sure the given vertex index isn't larger than the
                                                  // number of model vertices.
        return rescaled_pca_basis.block(vertex_id, 0, 3, rescaled_pca_basis.cols());
    };

    /**
     * Returns the PCA basis matrix, i.e. the eigenvectors.
     * Each column of the matrix is an eigenvector.
     * The returned basis is orthonormal, i.e. the eigenvectors
     * are not scaled by their respective eigenvalues.
     *
     * @return Returns the orthonormal PCA basis matrix.
     */
    const Eigen::MatrixXf& get_orthonormal_pca_basis() const
    {
        return orthonormal_pca_basis;
    };

    /**
     * Returns the PCA basis for a particular vertex, from the orthonormal basis.
     *
     * Note: The function does not return the i-th basis vector - it returns all basis
     * vectors, but only the block that is relevant for the vertex \p vertex_id.
     *
     * @param[in] vertex_id A vertex index. Make sure it is valid.
     * @return A 3 x num_principal_components matrix of the relevant rows of the original basis.
     */
    Eigen::MatrixXf get_orthonormal_pca_basis_at_point(int vertex_id) const
    {
        vertex_id *= 3;                           // the basis is stored in the format [x y z x y z ...]
        assert(vertex_id < get_data_dimension()); // Make sure the given vertex index isn't larger than the
                                                  // number of model vertices.
        return orthonormal_pca_basis.block(vertex_id, 0, 3, orthonormal_pca_basis.cols());
    };

    /**
     * Returns the models eigenvalues.
     *
     * @return The eigenvalues.
     */
    const Eigen::VectorXf& get_eigenvalues() const
    {
        return eigenvalues;
    };

    /**
     * Returns a specific eigenvalue.
     *
     * @param[in] index The index of the eigenvalue to return.
     * @return The eigenvalue.
     */
    float get_eigenvalue(int index) const
    {
        // no assert - Eigen checks access with an assert in debug builds
        return eigenvalues(index);
    };

private:
    Eigen::VectorXf mean; ///< A 3m x 1 col-vector (xyzxyz...)', where m is the number of model-vertices.
    Eigen::MatrixXf orthonormal_pca_basis; ///< m x n (rows x cols) = numShapeDims x numShapePcaCoeffs,
                                           ///< (=eigenvector matrix V). Each column is an eigenvector.
    Eigen::MatrixXf rescaled_pca_basis;    ///< m x n (rows x cols) = numShapeDims x numShapePcaCoeffs,
                                           ///< (=eigenvector matrix V). Each column is an eigenvector.
    Eigen::VectorXf eigenvalues;           ///< A col-vector of the eigenvalues (variances in the PCA space).

    std::vector<std::array<int, 3>> triangle_list; ///< List of triangles that make up the mesh of the model.

    friend class cereal::access;
    /**
     * Serialises this class using cereal.
     *
     * @param[in] archive The archive to serialise to (or to serialise from).
     */
    template <class Archive>
    void serialize(Archive& archive)
    {
        archive(CEREAL_NVP(mean), CEREAL_NVP(orthonormal_pca_basis), CEREAL_NVP(eigenvalues),
                CEREAL_NVP(triangle_list));
        // If we're loading, we have to recompute the rescaled basis, so that it's available (we don't
        // store it anymore):
        if (Archive::is_loading::value)
        {
            rescaled_pca_basis = rescale_pca_basis(orthonormal_pca_basis, eigenvalues);
        }
    };
};

/**
 * Helper method to load a PCA model from
 * a cereal::BinaryInputArchive from the harddisk.
 *
 * Usually, morphablemodel::load_model(std::string) should be used to directly
 * load a MorphableModel. This function can be useful when it is necessary to just
 * load a PCA model.
 *
 * @param[in] filename Filename to a model.
 * @return The loaded PCA model.
 * @throw std::runtime_error When the file given in \c filename fails to be opened (most likely because the
 * file doesn't exist).
 */
inline PcaModel load_pca_model(std::string filename)
{
    PcaModel model;

    std::ifstream file(filename, std::ios::binary);
    if (file.fail())
    {
        throw std::runtime_error("Error opening given file: " + filename);
    }
    cereal::BinaryInputArchive input_archive(file);
    input_archive(model);

    return model;
};

/**
 * Helper method to save a PCA model to the
 * harddrive as cereal::BinaryOutputArchive.
 *
 * @param[in] model The model to be saved.
 * @param[in] filename Filename for the model.
 */
inline void save_pca_model(PcaModel model, std::string filename)
{
    std::ofstream file(filename, std::ios::binary);
    cereal::BinaryOutputArchive output_archive(file);
    output_archive(model);
};

/**
 * Takes an orthonormal PCA basis matrix (a matrix consisting
 * of the eigenvectors) and rescales it, i.e. multiplies each
 * eigenvector by the square root of its corresponding
 * eigenvalue.
 *
 * @param[in] orthonormal_basis An orthonormal_basis PCA basis matrix.
 * @param[in] eigenvalues A row or column vector of eigenvalues.
 * @return The rescaled PCA basis matrix.
 */
inline Eigen::MatrixXf rescale_pca_basis(const Eigen::MatrixXf& orthonormal_basis,
                                         const Eigen::VectorXf& eigenvalues)
{
    Eigen::MatrixXf rescaled_basis(orthonormal_basis.rows(),
                                   orthonormal_basis.cols()); // empty matrix with the same dimensions
    const Eigen::VectorXf sqrt_of_eigenvalues = eigenvalues.array().sqrt();
    // Rescale the basis: We multiply each eigenvector (i.e. each column) with the square root of its
    // corresponding eigenvalue
    for (int basis = 0; basis < orthonormal_basis.cols(); ++basis)
    {
        rescaled_basis.col(basis) = orthonormal_basis.col(basis) * sqrt_of_eigenvalues(basis);
    }

    return rescaled_basis;
};

/**
 * Takes a rescaled PCA basis matrix and scales it back to
 * an orthonormal basis matrix by multiplying each eigenvector
 * by 1 over the square root of its corresponding eigenvalue.
 *
 * @param[in] rescaled_basis A rescaled PCA basis matrix.
 * @param[in] eigenvalues A row or column vector of eigenvalues.
 * @return The orthonormal PCA basis matrix.
 */
inline Eigen::MatrixXf normalise_pca_basis(const Eigen::MatrixXf& rescaled_basis,
                                           const Eigen::VectorXf& eigenvalues)
{
    Eigen::MatrixXf orthonormal_basis(rescaled_basis.rows(),
                                      rescaled_basis.cols()); // empty matrix with the same dimensions
    const Eigen::VectorXf one_over_sqrt_of_eigenvalues = eigenvalues.array().rsqrt();
    // "Normalise" the basis: We multiply each eigenvector (i.e. each column) with 1 over the square root of
    // its corresponding eigenvalue
    for (int basis = 0; basis < rescaled_basis.cols(); ++basis)
    {
        orthonormal_basis.col(basis) = rescaled_basis.col(basis) * one_over_sqrt_of_eigenvalues(basis);
    }

    return orthonormal_basis;
};

} /* namespace morphablemodel */
} /* namespace eos */

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


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

#pragma once

#include <algorithm>

#include "etl/impl/transpose.hpp"
#include "etl/impl/fft.hpp"

/*
 * Use CRTP technique to inject inplace operations into expressions and value classes.
 */

namespace etl {

template<typename D>
struct inplace_assignable {
    using derived_t = D;

    derived_t& as_derived() noexcept {
        return *static_cast<derived_t*>(this);
    }

    template<typename E>
    derived_t& scale_inplace(E&& e){
        as_derived() *= e;

        return as_derived();
    }

    derived_t& fflip_inplace(){
        static_assert(etl_traits<derived_t>::dimensions() <= 2, "Impossible to fflip a matrix of D > 2");

        if(etl_traits<derived_t>::dimensions() == 2){
            std::reverse(as_derived().begin(), as_derived().end());
        }

        return as_derived();
    }

    template<typename S = D, cpp_enable_if((decay_traits<S>::dimensions() > 3))>
    derived_t& deep_transpose_inplace(){
        decltype(auto) mat = as_derived();

        for(std::size_t i = 0; i < etl::dim<0>(mat); ++i){
            mat(i).deep_transpose_inplace();
        }

        return mat;
    }

    template<typename S = D, cpp_enable_if((decay_traits<S>::dimensions() == 3))>
    derived_t& deep_transpose_inplace(){
        decltype(auto) mat = as_derived();

        for(std::size_t i = 0; i < etl::dim<0>(mat); ++i){
            mat(i).transpose_inplace();
        }

        return mat;
    }

    template<typename S = D, cpp_disable_if(is_dyn_matrix<S>::value)>
    derived_t& transpose_inplace(){
        static_assert(etl_traits<derived_t>::dimensions() == 2, "Only 2D matrix can be transposed");
        cpp_assert(etl::dim<0>(as_derived()) == etl::dim<1>(as_derived()), "Only square matrices can be tranposed inplace");

        detail::inplace_square_transpose<derived_t>::apply(as_derived());

        return as_derived();
    }

    template<typename S = D, cpp_enable_if(is_dyn_matrix<S>::value)>
    derived_t& transpose_inplace(){
        static_assert(etl_traits<derived_t>::dimensions() == 2, "Only 2D matrix can be transposed");

        decltype(auto) mat = as_derived();

        if(etl::dim<0>(mat) == etl::dim<1>(mat)){
            detail::inplace_square_transpose<derived_t>::apply(mat);
        } else {
            detail::inplace_rectangular_transpose<derived_t>::apply(mat);

            using std::swap;
            swap(mat.unsafe_dimension_access(0), mat.unsafe_dimension_access(1));
        }

        return mat;
    }

    derived_t& fft_inplace(){
        static_assert(is_complex<derived_t>::value, "Only complex vector can use inplace FFT");
        static_assert(etl_traits<derived_t>::dimensions() == 1, "Only vector can use fft_inplace, use fft2_inplace for matrices");

        decltype(auto) mat = as_derived();

        detail::fft1_impl<derived_t, derived_t>::apply(mat, mat);

        return mat;
    }

    derived_t& fft_many_inplace(){
        static_assert(is_complex<derived_t>::value, "Only complex vector can use inplace FFT");
        static_assert(etl_traits<derived_t>::dimensions() > 1, "Only matrix of dimensions > 1 can use fft_many_inplace");

        decltype(auto) mat = as_derived();

        detail::fft1_many_impl<derived_t, derived_t>::apply(mat, mat);

        return mat;
    }

    derived_t& ifft_inplace(){
        static_assert(is_complex<derived_t>::value, "Only complex vector can use inplace IFFT");
        static_assert(etl_traits<derived_t>::dimensions() == 1, "Only vector can use ifft_inplace, use ifft2_inplace for matrices");

        decltype(auto) mat = as_derived();

        detail::ifft1_impl<derived_t, derived_t>::apply(mat, mat);

        return mat;
    }

    derived_t& fft2_inplace(){
        static_assert(is_complex<derived_t>::value, "Only complex vector can use inplace FFT");
        static_assert(etl_traits<derived_t>::dimensions() == 2, "Only matrix can use fft2_inplace, use fft_inplace for vectors");

        decltype(auto) mat = as_derived();

        detail::fft2_impl<derived_t, derived_t>::apply(mat, mat);

        return mat;
    }

    derived_t& fft2_many_inplace(){
        static_assert(is_complex<derived_t>::value, "Only complex vector can use inplace FFT");
        static_assert(etl_traits<derived_t>::dimensions() > 2, "Only matrix of dimensions > 2 can use fft2_many_inplace");

        decltype(auto) mat = as_derived();

        detail::fft2_many_impl<derived_t, derived_t>::apply(mat, mat);

        return mat;
    }

    derived_t& ifft2_inplace(){
        static_assert(is_complex<derived_t>::value, "Only complex vector can use inplace IFFT");
        static_assert(etl_traits<derived_t>::dimensions() == 2, "Only vector can use ifft_inplace, use ifft2_inplace for matrices");

        decltype(auto) mat = as_derived();

        detail::ifft2_impl<derived_t, derived_t>::apply(mat, mat);

        return mat;
    }
};

} //end of namespace etl
<commit_msg>Documentation<commit_after>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <algorithm>

#include "etl/impl/transpose.hpp"
#include "etl/impl/fft.hpp"

/*
 * Use CRTP technique to inject inplace operations into expressions and value classes.
 */

namespace etl {

template<typename D>
struct inplace_assignable {
    using derived_t = D;

    derived_t& as_derived() noexcept {
        return *static_cast<derived_t*>(this);
    }

    template<typename E>
    derived_t& scale_inplace(E&& e){
        as_derived() *= e;

        return as_derived();
    }

    derived_t& fflip_inplace(){
        static_assert(etl_traits<derived_t>::dimensions() <= 2, "Impossible to fflip a matrix of D > 2");

        if(etl_traits<derived_t>::dimensions() == 2){
            std::reverse(as_derived().begin(), as_derived().end());
        }

        return as_derived();
    }

    template<typename S = D, cpp_enable_if((decay_traits<S>::dimensions() > 3))>
    derived_t& deep_transpose_inplace(){
        decltype(auto) mat = as_derived();

        for(std::size_t i = 0; i < etl::dim<0>(mat); ++i){
            mat(i).deep_transpose_inplace();
        }

        return mat;
    }

    template<typename S = D, cpp_enable_if((decay_traits<S>::dimensions() == 3))>
    derived_t& deep_transpose_inplace(){
        decltype(auto) mat = as_derived();

        for(std::size_t i = 0; i < etl::dim<0>(mat); ++i){
            mat(i).transpose_inplace();
        }

        return mat;
    }

    template<typename S = D, cpp_disable_if(is_dyn_matrix<S>::value)>
    derived_t& transpose_inplace(){
        static_assert(etl_traits<derived_t>::dimensions() == 2, "Only 2D matrix can be transposed");
        cpp_assert(etl::dim<0>(as_derived()) == etl::dim<1>(as_derived()), "Only square matrices can be tranposed inplace");

        detail::inplace_square_transpose<derived_t>::apply(as_derived());

        return as_derived();
    }

    template<typename S = D, cpp_enable_if(is_dyn_matrix<S>::value)>
    derived_t& transpose_inplace(){
        static_assert(etl_traits<derived_t>::dimensions() == 2, "Only 2D matrix can be transposed");

        decltype(auto) mat = as_derived();

        if(etl::dim<0>(mat) == etl::dim<1>(mat)){
            detail::inplace_square_transpose<derived_t>::apply(mat);
        } else {
            detail::inplace_rectangular_transpose<derived_t>::apply(mat);

            using std::swap;
            swap(mat.unsafe_dimension_access(0), mat.unsafe_dimension_access(1));
        }

        return mat;
    }

    /*!
     * \brief Perform inplace 1D FFT of the vector.
     */
    derived_t& fft_inplace(){
        static_assert(is_complex<derived_t>::value, "Only complex vector can use inplace FFT");
        static_assert(etl_traits<derived_t>::dimensions() == 1, "Only vector can use fft_inplace, use fft2_inplace for matrices");

        decltype(auto) mat = as_derived();

        detail::fft1_impl<derived_t, derived_t>::apply(mat, mat);

        return mat;
    }

    derived_t& fft_many_inplace(){
        static_assert(is_complex<derived_t>::value, "Only complex vector can use inplace FFT");
        static_assert(etl_traits<derived_t>::dimensions() > 1, "Only matrix of dimensions > 1 can use fft_many_inplace");

        decltype(auto) mat = as_derived();

        detail::fft1_many_impl<derived_t, derived_t>::apply(mat, mat);

        return mat;
    }

    derived_t& ifft_inplace(){
        static_assert(is_complex<derived_t>::value, "Only complex vector can use inplace IFFT");
        static_assert(etl_traits<derived_t>::dimensions() == 1, "Only vector can use ifft_inplace, use ifft2_inplace for matrices");

        decltype(auto) mat = as_derived();

        detail::ifft1_impl<derived_t, derived_t>::apply(mat, mat);

        return mat;
    }

    derived_t& fft2_inplace(){
        static_assert(is_complex<derived_t>::value, "Only complex vector can use inplace FFT");
        static_assert(etl_traits<derived_t>::dimensions() == 2, "Only matrix can use fft2_inplace, use fft_inplace for vectors");

        decltype(auto) mat = as_derived();

        detail::fft2_impl<derived_t, derived_t>::apply(mat, mat);

        return mat;
    }

    derived_t& fft2_many_inplace(){
        static_assert(is_complex<derived_t>::value, "Only complex vector can use inplace FFT");
        static_assert(etl_traits<derived_t>::dimensions() > 2, "Only matrix of dimensions > 2 can use fft2_many_inplace");

        decltype(auto) mat = as_derived();

        detail::fft2_many_impl<derived_t, derived_t>::apply(mat, mat);

        return mat;
    }

    derived_t& ifft2_inplace(){
        static_assert(is_complex<derived_t>::value, "Only complex vector can use inplace IFFT");
        static_assert(etl_traits<derived_t>::dimensions() == 2, "Only vector can use ifft_inplace, use ifft2_inplace for matrices");

        decltype(auto) mat = as_derived();

        detail::ifft2_impl<derived_t, derived_t>::apply(mat, mat);

        return mat;
    }
};

} //end of namespace etl
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

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

#ifndef FLUSSPFERD_FUNCTION_ADAPTER_HPP
#define FLUSSPFERD_FUNCTION_ADAPTER_HPP

#ifndef PREPROC_DEBUG
#include "convert.hpp"
#include "call_context.hpp"
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/function.hpp>
#endif
#include <boost/preprocessor.hpp>

#ifndef FLUSSPFERD_PARAM_LIMIT
#define FLUSSPFERD_PARAM_LIMIT 5
#endif

namespace flusspferd {

class native_object_base;

template<typename T>
T &cast_to_derived(native_object_base &);

#ifndef IN_DOXYGEN

namespace detail {

template<typename T>
struct is_native_object_type {
  typedef typename boost::remove_reference<T>::type T1;
  typedef typename boost::remove_pointer<T1>::type naked_type;

  typedef typename boost::is_base_of<native_object_base, naked_type>::type type;
};

template<typename T, typename Condition = void>
struct ptr_to_native_object_type {
  typedef typename is_native_object_type<T>::naked_type naked_type;

  static T get(native_object_base &self_native) {
    return cast_to_derived<naked_type>(self_native);
  }
};

template<typename T>
struct ptr_to_native_object_type<
    T, typename boost::enable_if<typename boost::is_pointer<T>::type>::type>
{
  typedef typename is_native_object_type<T>::naked_type naked_type;

  static T get(native_object_base &self_native) {
    return &cast_to_derived<naked_type>(self_native);
  }
};

native_object_base &get_native_object_parameter_ptr(call_context &x);

template<typename T>
typename T::arg1_type
get_native_object_parameter(call_context &x) {
  native_object_base &p = get_native_object_parameter_ptr(x);
  return ptr_to_native_object_type<typename T::arg1_type>::get(p);
}

template<typename T>
T get_native_object_parameter2(call_context &x) {
  native_object_base &p = get_native_object_parameter_ptr(x);
  return ptr_to_native_object_type<T>::get(p);
}

#define FLUSSPFERD_DECLARE_ARG_CONVERTER(z, i, T) \
  typename convert<typename T::BOOST_PP_CAT(BOOST_PP_CAT(arg, i), _type)>::from_value \
  BOOST_PP_CAT(BOOST_PP_CAT(arg, i), _from_value); \
  /* */

#define FLUSSPFERD_DECLARE_ARG_CONVERTERS(first, last, T) \
  BOOST_PP_REPEAT_FROM_TO( \
    first, \
    BOOST_PP_INC(last), \
    FLUSSPFERD_DECLARE_ARG_CONVERTER, \
    T) \
  /* */

#define FLUSSPFERD_CONVERT_ARG(z, i, offset) \
  BOOST_PP_COMMA_IF(BOOST_PP_GREATER(i, 1)) \
  BOOST_PP_CAT(BOOST_PP_CAT(arg, i), _from_value) \
  .perform((x).arg[BOOST_PP_SUB(BOOST_PP_DEC(i), offset)]) \
  /* */

#define FLUSSPFERD_CONVERT_ARGS(first, last, offset) \
  BOOST_PP_REPEAT_FROM_TO( \
    first, \
    BOOST_PP_INC(last), \
    FLUSSPFERD_CONVERT_ARG, \
    offset) \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_(z, n_args, d) \
  template<typename T, typename R, typename C> \
  struct function_adapter<T, false, R, n_args, C> { \
    typename convert<R>::to_value to_value; \
    FLUSSPFERD_DECLARE_ARG_CONVERTERS(1, n_args, T) \
    void action(T const &function, call_context &x) { \
      x.result = to_value.perform( \
        function(FLUSSPFERD_CONVERT_ARGS(1, n_args, 0))); \
    } \
    static std::size_t const arity = (n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_R_VOID(z, n_args, d) \
  template<typename T, typename C> \
  struct function_adapter<T, false, void, n_args, C> { \
    FLUSSPFERD_DECLARE_ARG_CONVERTERS(1, n_args, T) \
    void action(T const &function, call_context &x) { \
      (void)x; \
      function(FLUSSPFERD_CONVERT_ARGS(1, n_args, 0)); \
    } \
    static std::size_t const arity = (n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_NATIVE_OBJECT(z, n_args, d) \
  template<typename T, typename R> \
  struct function_adapter< \
    T, true, R, n_args, \
    typename boost::enable_if< \
      typename is_native_object_type<typename T::arg1_type>::type \
    >::type \
  > \
  { \
    typename convert<R>::to_value to_value; \
    FLUSSPFERD_DECLARE_ARG_CONVERTERS(2, n_args, T) \
    void action(T const &function, call_context &x) { \
      x.result = to_value.perform( \
        function( \
          get_native_object_parameter<T>(x) \
          FLUSSPFERD_CONVERT_ARGS(2, n_args, 1) \
        )); \
    } \
    static std::size_t const arity = BOOST_PP_DEC(n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_NATIVE_OBJECT_R_VOID(z, n_args, d) \
  template<typename T> \
  struct function_adapter< \
    T, true, void, n_args, \
    typename boost::enable_if< \
      typename is_native_object_type<typename T::arg1_type>::type \
    >::type \
  > \
  { \
    FLUSSPFERD_DECLARE_ARG_CONVERTERS(2, n_args, T) \
    void action(T const &function, call_context &x) { \
      function( \
        get_native_object_parameter<T>(x) \
        FLUSSPFERD_CONVERT_ARGS(2, n_args, 1) \
      ); \
    } \
    static std::size_t const arity = BOOST_PP_DEC(n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_OBJECT(z, n_args, d) \
  template<typename T, typename R> \
  struct function_adapter< \
    T, true, R, n_args, \
    typename boost::enable_if< \
      typename boost::is_convertible<object, typename T::arg1_type>::type \
    >::type \
  > \
  { \
    typename convert<R>::to_value to_value; \
    FLUSSPFERD_DECLARE_ARG_CONVERTERS(2, n_args, T) \
    void action(T const &function, call_context &x) { \
      x.result = to_value.perform(function( \
          x.self \
          FLUSSPFERD_CONVERT_ARGS(2, n_args, 1) \
        )); \
    } \
    static std::size_t const arity = BOOST_PP_DEC(n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_OBJECT_R_VOID(z, n_args, d) \
  template<typename T> \
  struct function_adapter< \
    T, true, void, n_args, \
    typename boost::enable_if< \
      typename boost::is_convertible<object, typename T::arg1_type>::type \
    >::type \
  > \
  { \
    FLUSSPFERD_DECLARE_ARG_CONVERTERS(2, n_args, T) \
    void action(T const &function, call_context &x) { \
      function( \
        x.self \
        FLUSSPFERD_CONVERT_ARGS(2, n_args, 1) \
      ); \
    } \
    static std::size_t const arity = BOOST_PP_DEC(n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_ARG_CONVERTER_MEMFN(z, i, d) \
  typename convert<BOOST_PP_CAT(P, i)>::from_value \
  BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(i)), _from_value);

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_MEMFN(z, n_args, d) \
  template< \
    typename T, \
    typename R \
    BOOST_PP_ENUM_TRAILING_PARAMS(n_args, typename P) \
  > \
  struct function_adapter_memfn< \
    R (BOOST_PP_ENUM_PARAMS(n_args, P)), T \
  > \
  { \
    typename convert<R>::to_value to_value; \
    BOOST_PP_REPEAT(n_args, FLUSSPFERD_DECLARE_ARG_CONVERTER_MEMFN, ~) \
    template<typename F> \
    void action(F fun, call_context &x) { \
      x.result = to_value.perform( \
        (get_native_object_parameter2<T*>(x)->*fun) \
          (FLUSSPFERD_CONVERT_ARGS(1, n_args, 0))); \
    } \
    static std::size_t const arity = (n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_MEMFN_R_VOID(z, n_args, d) \
  template< \
    typename T \
    BOOST_PP_ENUM_TRAILING_PARAMS(n_args, typename P) \
  > \
  struct function_adapter_memfn< \
    void (BOOST_PP_ENUM_PARAMS(n_args, P)), T \
  > \
  { \
    BOOST_PP_REPEAT(n_args, FLUSSPFERD_DECLARE_ARG_CONVERTER_MEMFN, ~) \
    template<typename F> \
    void action(F fun, call_context &x) { \
      (get_native_object_parameter2<T*>(x)->*fun) \
          (FLUSSPFERD_CONVERT_ARGS(1, n_args, 0)); \
    } \
    static std::size_t const arity = (n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(suffix) \
  BOOST_PP_REPEAT_FROM_TO( \
    0, \
    BOOST_PP_INC(FLUSSPFERD_PARAM_LIMIT), \
    BOOST_PP_CAT(FLUSSPFERD_DECLARE_FUNCTION_ADAPTER, suffix), \
    ~) \
  /* */

template<
  typename Type,
  bool Method,
  typename ResultType = typename Type::result_type,
  std::size_t Arity = Type::arity,
  typename Condition = void>
struct function_adapter;

template<
  typename R,
  typename T
> struct function_adapter_memfn;

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_R_VOID)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_NATIVE_OBJECT)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_NATIVE_OBJECT_R_VOID)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_OBJECT)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_OBJECT_R_VOID)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_MEMFN)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_MEMFN_R_VOID)

}

#endif

/**
 * Function adapter.
 *
 * @ingroup functions
 */
template<typename T, bool Method>
class function_adapter {
public:
  typedef T spec_type;
  typedef boost::function<spec_type> function_type;

private:
  typedef detail::function_adapter<function_type, Method> adapter_type;

public:
  function_adapter(function_type const &function)
    : function(function)
  {}

  void operator() (call_context &x) {
    adapter_type function_adapter_implementation;
    function_adapter_implementation.action(function, x);
  }

  static std::size_t const arity =
    adapter_type::arity;

private:
  function_type function;
};

/**
 * Function adapter.
 *
 * @ingroup functions
 */
template<typename R, typename T>
class function_adapter_memfn {
private:
  typedef detail::function_adapter_memfn<R, T> adapter_type;

public:
  function_adapter_memfn(R T::*funptr)
    : funptr(funptr)
  {}

  void operator() (call_context &x) {
    adapter_type function_adapter_implementation_memfn;
    function_adapter_implementation_memfn.action(funptr, x);
  }

  static std::size_t const arity =
    adapter_type::arity;

private:
  R T::*funptr;
};

}

#include "native_object_base.hpp"

#endif
<commit_msg>nothing drastic<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

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

#ifndef FLUSSPFERD_FUNCTION_ADAPTER_HPP
#define FLUSSPFERD_FUNCTION_ADAPTER_HPP

#ifndef PREPROC_DEBUG
#include "convert.hpp"
#include "call_context.hpp"
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/function.hpp>
#endif
#include <boost/preprocessor.hpp>

#ifndef FLUSSPFERD_PARAM_LIMIT
#define FLUSSPFERD_PARAM_LIMIT 5
#endif

namespace flusspferd {

class native_object_base;

template<typename T>
T &cast_to_derived(native_object_base &);

#ifndef IN_DOXYGEN

namespace detail {

template<typename T>
struct is_native_object_type {
  typedef typename boost::remove_reference<T>::type T1;
  typedef typename boost::remove_pointer<T1>::type naked_type;

  typedef typename boost::is_base_of<native_object_base, naked_type>::type type;
};

template<typename T, typename Condition = void>
struct ptr_to_native_object_type {
  typedef typename is_native_object_type<T>::naked_type naked_type;

  static T get(native_object_base &self_native) {
    return cast_to_derived<naked_type>(self_native);
  }
};

template<typename T>
struct ptr_to_native_object_type<
    T, typename boost::enable_if<typename boost::is_pointer<T>::type>::type>
{
  typedef typename is_native_object_type<T>::naked_type naked_type;

  static T get(native_object_base &self_native) {
    return &cast_to_derived<naked_type>(self_native);
  }
};

native_object_base &get_native_object_parameter_ptr(call_context &x);

template<typename T>
typename T::arg1_type
get_native_object_parameter(call_context &x) {
  native_object_base &p = get_native_object_parameter_ptr(x);
  return ptr_to_native_object_type<typename T::arg1_type>::get(p);
}

template<typename T>
T get_native_object_parameter2(call_context &x) {
  native_object_base &p = get_native_object_parameter_ptr(x);
  return ptr_to_native_object_type<T>::get(p);
}

#define FLUSSPFERD_DECLARE_ARG_CONVERTER(z, i, T) \
  typename convert<typename T::BOOST_PP_CAT(BOOST_PP_CAT(arg, i), _type)>::from_value \
  BOOST_PP_CAT(BOOST_PP_CAT(arg, i), _from_value); \
  /* */

#define FLUSSPFERD_DECLARE_ARG_CONVERTERS(first, last, T) \
  BOOST_PP_REPEAT_FROM_TO( \
    first, \
    BOOST_PP_INC(last), \
    FLUSSPFERD_DECLARE_ARG_CONVERTER, \
    T) \
  /* */

#define FLUSSPFERD_CONVERT_ARG(z, i, offset) \
  BOOST_PP_COMMA_IF(BOOST_PP_GREATER(i, 1)) \
  BOOST_PP_CAT(BOOST_PP_CAT(arg, i), _from_value) \
  .perform((x).arg[BOOST_PP_SUB(BOOST_PP_DEC(i), offset)]) \
  /* */

#define FLUSSPFERD_CONVERT_ARGS(first, last, offset) \
  BOOST_PP_REPEAT_FROM_TO( \
    first, \
    BOOST_PP_INC(last), \
    FLUSSPFERD_CONVERT_ARG, \
    offset) \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_(z, n_args, d) \
  template<typename T, typename R, typename C> \
  struct function_adapter<T, false, R, n_args, C> { \
    typename convert<R>::to_value to_value; \
    FLUSSPFERD_DECLARE_ARG_CONVERTERS(1, n_args, T) \
    void action(T const &function, call_context &x) { \
      x.result = to_value.perform( \
        function(FLUSSPFERD_CONVERT_ARGS(1, n_args, 0))); \
    } \
    static std::size_t const arity = (n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_R_VOID(z, n_args, d) \
  template<typename T, typename C> \
  struct function_adapter<T, false, void, n_args, C> { \
    FLUSSPFERD_DECLARE_ARG_CONVERTERS(1, n_args, T) \
    void action(T const &function, call_context &x) { \
      (void)x; \
      function(FLUSSPFERD_CONVERT_ARGS(1, n_args, 0)); \
    } \
    static std::size_t const arity = (n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_NATIVE_OBJECT(z, n_args, d) \
  template<typename T, typename R> \
  struct function_adapter< \
    T, true, R, n_args, \
    typename boost::enable_if< \
      typename is_native_object_type<typename T::arg1_type>::type \
    >::type \
  > \
  { \
    typename convert<R>::to_value to_value; \
    FLUSSPFERD_DECLARE_ARG_CONVERTERS(2, n_args, T) \
    void action(T const &function, call_context &x) { \
      x.result = to_value.perform( \
        function( \
          get_native_object_parameter<T>(x) \
          FLUSSPFERD_CONVERT_ARGS(2, n_args, 1) \
        )); \
    } \
    static std::size_t const arity = BOOST_PP_DEC(n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_NATIVE_OBJECT_R_VOID(z, n_args, d) \
  template<typename T> \
  struct function_adapter< \
    T, true, void, n_args, \
    typename boost::enable_if< \
      typename is_native_object_type<typename T::arg1_type>::type \
    >::type \
  > \
  { \
    FLUSSPFERD_DECLARE_ARG_CONVERTERS(2, n_args, T) \
    void action(T const &function, call_context &x) { \
      function( \
        get_native_object_parameter<T>(x) \
        FLUSSPFERD_CONVERT_ARGS(2, n_args, 1) \
      ); \
    } \
    static std::size_t const arity = BOOST_PP_DEC(n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_OBJECT(z, n_args, d) \
  template<typename T, typename R> \
  struct function_adapter< \
    T, true, R, n_args, \
    typename boost::enable_if< \
      typename boost::is_convertible<object, typename T::arg1_type>::type \
    >::type \
  > \
  { \
    typename convert<R>::to_value to_value; \
    FLUSSPFERD_DECLARE_ARG_CONVERTERS(2, n_args, T) \
    void action(T const &function, call_context &x) { \
      x.result = to_value.perform(function( \
          x.self \
          FLUSSPFERD_CONVERT_ARGS(2, n_args, 1) \
        )); \
    } \
    static std::size_t const arity = BOOST_PP_DEC(n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_OBJECT_R_VOID(z, n_args, d) \
  template<typename T> \
  struct function_adapter< \
    T, true, void, n_args, \
    typename boost::enable_if< \
      typename boost::is_convertible<object, typename T::arg1_type>::type \
    >::type \
  > \
  { \
    FLUSSPFERD_DECLARE_ARG_CONVERTERS(2, n_args, T) \
    void action(T const &function, call_context &x) { \
      function( \
        x.self \
        FLUSSPFERD_CONVERT_ARGS(2, n_args, 1) \
      ); \
    } \
    static std::size_t const arity = BOOST_PP_DEC(n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_ARG_CONVERTER_MEMFN(z, i, d) \
  typename convert<BOOST_PP_CAT(P, i)>::from_value \
  BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(i)), _from_value);

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_MEMFN(z, n_args, d) \
  template< \
    typename T, \
    typename R \
    BOOST_PP_ENUM_TRAILING_PARAMS(n_args, typename P) \
  > \
  struct function_adapter_memfn< \
    R (BOOST_PP_ENUM_PARAMS(n_args, P)), T \
  > \
  { \
    typename convert<R>::to_value to_value; \
    BOOST_PP_REPEAT(n_args, FLUSSPFERD_DECLARE_ARG_CONVERTER_MEMFN, ~) \
    template<typename F> \
    void action(F fun, call_context &x) { \
      x.result = to_value.perform( \
        (get_native_object_parameter2<T*>(x)->*fun) \
          (FLUSSPFERD_CONVERT_ARGS(1, n_args, 0))); \
    } \
    static std::size_t const arity = (n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTER_MEMFN_R_VOID(z, n_args, d) \
  template< \
    typename T \
    BOOST_PP_ENUM_TRAILING_PARAMS(n_args, typename P) \
  > \
  struct function_adapter_memfn< \
    void (BOOST_PP_ENUM_PARAMS(n_args, P)), T \
  > \
  { \
    BOOST_PP_REPEAT(n_args, FLUSSPFERD_DECLARE_ARG_CONVERTER_MEMFN, ~) \
    template<typename F> \
    void action(F fun, call_context &x) { \
      (get_native_object_parameter2<T*>(x)->*fun) \
          (FLUSSPFERD_CONVERT_ARGS(1, n_args, 0)); \
    } \
    static std::size_t const arity = (n_args); \
  }; \
  /* */

#define FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(suffix) \
  BOOST_PP_REPEAT_FROM_TO( \
    0, \
    BOOST_PP_INC(FLUSSPFERD_PARAM_LIMIT), \
    BOOST_PP_CAT(FLUSSPFERD_DECLARE_FUNCTION_ADAPTER, suffix), \
    ~) \
  /* */

template<
  typename Type,
  bool Method,
  typename ResultType = typename Type::result_type,
  std::size_t Arity = Type::arity,
  typename Condition = void>
struct function_adapter;

template<
  typename R,
  typename T
> struct function_adapter_memfn;

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_R_VOID)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_NATIVE_OBJECT)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_NATIVE_OBJECT_R_VOID)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_OBJECT)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_OBJECT_R_VOID)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_MEMFN)

FLUSSPFERD_DECLARE_FUNCTION_ADAPTERS(_MEMFN_R_VOID)

}

#endif

/**
 * Function adapter.
 *
 * @ingroup functions
 */
template<typename T, bool Method>
class function_adapter {
public:
  typedef T spec_type;
  typedef boost::function<spec_type> function_type;

private:
  typedef detail::function_adapter<function_type, Method> adapter_type;

public:
  function_adapter(function_type const &function)
    : function(function)
  {}

  void operator() (call_context &x) {
    adapter_type function_adapter_implementation;
    function_adapter_implementation.action(function, x);
  }

  static std::size_t const arity = adapter_type::arity;

private:
  function_type function;
};

/**
 * Function adapter.
 *
 * @ingroup functions
 */
template<typename R, typename T>
class function_adapter_memfn {
private:
  typedef detail::function_adapter_memfn<R, T> adapter_type;

public:
  function_adapter_memfn(R T::*funptr)
    : funptr(funptr)
  {}

  void operator() (call_context &x) {
    adapter_type function_adapter_implementation_memfn;
    function_adapter_implementation_memfn.action(funptr, x);
  }

  static std::size_t const arity = adapter_type::arity;

private:
  R T::*funptr;
};

}

#include "native_object_base.hpp"

#endif
<|endoftext|>


<commit_before>/*
 * SimpleConfigurator.hh
 *
 * Copyright 2001, Glen Scott. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */
#ifndef _LOG4CPP_PROPERTYCONFIGURATOR_HH
#define _LOG4CPP_PROPERTYCONFIGURATOR_HH

#include <log4cpp/Portability.hh>
#include <log4cpp/Export.hh>

#include <string>
#include <log4cpp/Configurator.hh>	// configure exceptions

namespace log4cpp {

    /**
       Property configurator will read a config file using the same (or similar)
       format to the config file used by log4j. This file is in a standard Java
       "properties" file format.

Example:

       # a simple test config

       log4j.rootCategory=DEBUG, rootAppender
       log4j.category.sub1=A1
       log4j.category.sub2=INFO
       log4j.category.sub1.sub2=ERROR, A2

       log4j.appender.rootAppender=org.apache.log4j.ConsoleAppender
       log4j.appender.rootAppender.layout=org.apache.log4j.BasicLayout

       log4j.appender.A1=org.apache.log4j.FileAppender
       log4j.appender.A1.fileName=A1.log
       log4j.appender.A1.layout=org.apache.log4j.BasicLayout

       log4j.appender.A2=org.apache.log4j.ConsoleAppender
       log4j.appender.A2.layout=org.apache.log4j.PatternLayout
       log4j.appender.A2.layout.pattern=The message %%m at time %%d%%n

       @since 0.3.2
    **/
    class LOG4CPP_EXPORT PropertyConfigurator {
        public:
        static void configure(const std::string& initFileName) throw (ConfigureFailure);
    };
}

#endif // _LOG4CPP_PROPERTYCONFIGURATOR_HH
<commit_msg>ConversionPattern instead of pattern (patch #692193).<commit_after>/*
 * SimpleConfigurator.hh
 *
 * Copyright 2001, Glen Scott. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */
#ifndef _LOG4CPP_PROPERTYCONFIGURATOR_HH
#define _LOG4CPP_PROPERTYCONFIGURATOR_HH

#include <log4cpp/Portability.hh>
#include <log4cpp/Export.hh>

#include <string>
#include <log4cpp/Configurator.hh>	// configure exceptions

namespace log4cpp {

    /**
       Property configurator will read a config file using the same (or similar)
       format to the config file used by log4j. This file is in a standard Java
       "properties" file format.

Example:

       # a simple test config

       log4j.rootCategory=DEBUG, rootAppender
       log4j.category.sub1=A1
       log4j.category.sub2=INFO
       log4j.category.sub1.sub2=ERROR, A2

       log4j.appender.rootAppender=org.apache.log4j.ConsoleAppender
       log4j.appender.rootAppender.layout=org.apache.log4j.BasicLayout

       log4j.appender.A1=org.apache.log4j.FileAppender
       log4j.appender.A1.fileName=A1.log
       log4j.appender.A1.layout=org.apache.log4j.BasicLayout

       log4j.appender.A2=org.apache.log4j.ConsoleAppender
       log4j.appender.A2.layout=org.apache.log4j.PatternLayout
       log4j.appender.A2.layout.ConversionPattern=The message %%m at time %%d%%n

       @since 0.3.2
    **/
    class LOG4CPP_EXPORT PropertyConfigurator {
        public:
        static void configure(const std::string& initFileName) throw (ConfigureFailure);
    };
}

#endif // _LOG4CPP_PROPERTYCONFIGURATOR_HH
<|endoftext|>