<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)
//=======================================================================

#pragma once

#include "etl/impl/std/fft.hpp"
#include "etl/impl/blas/fft.hpp"
#include "etl/impl/cufft/fft.hpp"

namespace etl {

namespace detail {

enum class fft_impl {
    STD,
    MKL,
    CUFFT
};

enum class precision {
    S,
    D,
    C,
    Z
};

inline constexpr bool is_power_of_two(long n) {
    return (n & (n - 1)) == 0;
}

inline cpp14_constexpr fft_impl select_fft1_impl(const std::size_t n) {
    //Note since these boolean will be known at compile time, the conditions will be a lot simplified
    constexpr const bool mkl   = is_mkl_enabled::value;
    constexpr const bool cufft = is_cufft_enabled::value;

    if (cufft) {
        if (is_power_of_two(n)) {
            if (n <= 64) {
                return fft_impl::STD;
            } else if (n <= 1024) {
                if (mkl) {
                    return fft_impl::MKL;
                } else {
                    return fft_impl::STD;
                }
            } else if (n <= 65536 && mkl) {
                return fft_impl::MKL;
            }

            return fft_impl::CUFFT;
        }

        if (n <= 250000 && mkl) {
            return fft_impl::MKL;
        }

        return fft_impl::CUFFT;
    } else if (mkl) {
        if (is_power_of_two(n) && n <= 64) {
            return fft_impl::STD;
        }

        return fft_impl::MKL;
    } else {
        return fft_impl::STD;
    }
}

inline cpp14_constexpr fft_impl select_fft1_many_impl(const std::size_t /*batch*/, const std::size_t n) {
    //Note since these boolean will be known at compile time, the conditions will be a lot simplified
    constexpr const bool mkl   = is_mkl_enabled::value;
    constexpr const bool cufft = is_cufft_enabled::value;

    //Note: more testing would probably improve this selection

    if (cufft) {
        if (n <= 250000 && mkl) {
            return fft_impl::MKL;
        }

        return fft_impl::CUFFT;
    } else if (mkl) {
        return fft_impl::MKL;
    } else {
        return fft_impl::STD;
    }
}

inline cpp14_constexpr fft_impl select_ifft1_impl(const std::size_t n) {
    //Note since these boolean will be known at compile time, the conditions will be a lot simplified
    constexpr const bool mkl   = is_mkl_enabled::value;
    constexpr const bool cufft = is_cufft_enabled::value;

    if (cufft) {
        if (is_power_of_two(n)) {
            if (n <= 1024) {
                if (mkl) {
                    return fft_impl::MKL;
                } else {
                    return fft_impl::STD;
                }
            } else if (n <= 262144 && mkl) {
                return fft_impl::MKL;
            }

            return fft_impl::CUFFT;
        }

        if (n <= 250000 && mkl) {
            return fft_impl::MKL;
        }

        return fft_impl::CUFFT;
    } else if (mkl) {
        return fft_impl::MKL;
    } else {
        return fft_impl::STD;
    }
}

inline cpp14_constexpr fft_impl select_fft2_impl(const std::size_t n1, std::size_t n2) {
    //Note since these boolean will be known at compile time, the conditions will be a lot simplified
    constexpr const bool mkl   = is_mkl_enabled::value;
    constexpr const bool cufft = is_cufft_enabled::value;

    if (cufft) {
        if (is_power_of_two(n1) && is_power_of_two(n2)) {
            if (n1 * n2 < 150 * 150) {
                if (mkl) {
                    return fft_impl::MKL;
                } else {
                    return fft_impl::STD;
                }
            } else if (n1 * n2 <= 768 * 768 && mkl) {
                return fft_impl::MKL;
            }

            return fft_impl::CUFFT;
        }

        if (n1 * n2 <= 768 * 768 && mkl) {
            return fft_impl::MKL;
        }

        return fft_impl::CUFFT;
    } else if (mkl) {
        return fft_impl::MKL;
    } else {
        return fft_impl::STD;
    }
}

inline cpp14_constexpr fft_impl select_fft2_many_impl(const std::size_t /*batch*/, const std::size_t n1, const std::size_t n2) {
    //Note since these boolean will be known at compile time, the conditions will be a lot simplified
    constexpr const bool mkl   = is_mkl_enabled::value;
    constexpr const bool cufft = is_cufft_enabled::value;

    //Note: more testing would probably improve this selection

    if (cufft) {
        if (n1 * n2 <= 768 * 768 && mkl) {
            return fft_impl::MKL;
        }

        return fft_impl::CUFFT;
    } else if (mkl) {
        return fft_impl::MKL;
    } else {
        return fft_impl::STD;
    }
}

template <typename A, typename C>
struct fft1_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_fft1_impl(etl::size(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::fft1(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::fft1(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::fft1(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct ifft1_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_ifft1_impl(etl::size(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::ifft1(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::ifft1(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::ifft1(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct ifft1_real_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_ifft1_impl(etl::size(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::ifft1_real(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::ifft1_real(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::ifft1_real(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct fft2_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_fft2_impl(etl::dim<0>(c), etl::dim<1>(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::fft2(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::fft2(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::fft2(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct ifft2_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_fft2_impl(etl::dim<0>(c), etl::dim<1>(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::ifft2(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::ifft2(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::ifft2(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct ifft2_real_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_fft2_impl(etl::dim<0>(c), etl::dim<1>(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::ifft2_real(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::ifft2_real(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::ifft2_real(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct fft1_many_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_fft1_many_impl(etl::dim<0>(c), etl::dim<1>(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::fft1_many(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::fft1_many(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::fft1_many(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct fft2_many_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_fft2_many_impl(etl::dim<0>(c), etl::dim<1>(c), etl::dim<2>(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::fft2_many(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::fft2_many(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::fft2_many(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename B, typename C, typename Enable = void>
struct fft_conv1_full_impl {
    template <typename AA, typename BB, typename CC>
    static void apply(AA&& a, BB&& b, CC&& c) {
        if(is_cufft_enabled::value){
            etl::impl::cufft::fft1_convolve(std::forward<AA>(a), std::forward<BB>(b), std::forward<CC>(c));
        } else if(is_mkl_enabled::value){
            etl::impl::blas::fft1_convolve(std::forward<AA>(a), std::forward<BB>(b), std::forward<CC>(c));
        } else {
            etl::impl::standard::fft1_convolve(std::forward<AA>(a), std::forward<BB>(b), std::forward<CC>(c));
        }
    }
};

template <typename A, typename B, typename C, typename Enable = void>
struct fft_conv2_full_impl {
    template <typename AA, typename BB, typename CC>
    static void apply(AA&& a, BB&& b, CC&& c) {
        if(is_cufft_enabled::value){
            etl::impl::cufft::fft2_convolve(std::forward<AA>(a), std::forward<BB>(b), std::forward<CC>(c));
        } else if(is_mkl_enabled::value){
            etl::impl::blas::fft2_convolve(std::forward<AA>(a), std::forward<BB>(b), std::forward<CC>(c));
        } else {
            etl::impl::standard::fft2_convolve(std::forward<AA>(a), std::forward<BB>(b), std::forward<CC>(c));
        }
    }
};

} //end of namespace detail

} //end of namespace etl
<commit_msg>Doc and clean<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)
//=======================================================================

#pragma once

#include "etl/impl/std/fft.hpp"
#include "etl/impl/blas/fft.hpp"
#include "etl/impl/cufft/fft.hpp"

namespace etl {

namespace detail {

/*!
 * \brief The different FFT implementations
 */
enum class fft_impl {
    STD,  ///< The standard implementation
    MKL,  ///< The Intel MKL implementation
    CUFFT ///< The NVidia CuFFT implementation
};

/*!
 * \brief The precision of the operation
 */
enum class precision {
    S, ///< Single precision
    D, ///< Double precision
    C, ///< Single complex precision
    Z  ///< Double complex precision
};

/*!
 * \brief Test if the given number is a power of two
 * \param n The number to test
 * \return true if the number is a power of two, false otherwise
 */
inline constexpr bool is_power_of_two(long n) {
    return (n & (n - 1)) == 0;
}

/*!
 * \brief Select a 1D FFT implementation based on the operation size
 * \param n The size of the operation
 * \return The implementation to use
 */
inline cpp14_constexpr fft_impl select_fft1_impl(const std::size_t n) {
    //Note since these boolean will be known at compile time, the conditions will be a lot simplified
    constexpr const bool mkl   = is_mkl_enabled::value;
    constexpr const bool cufft = is_cufft_enabled::value;

    if (cufft) {
        if (is_power_of_two(n)) {
            if (n <= 64) {
                return fft_impl::STD;
            } else if (n <= 1024) {
                if (mkl) {
                    return fft_impl::MKL;
                } else {
                    return fft_impl::STD;
                }
            } else if (n <= 65536 && mkl) {
                return fft_impl::MKL;
            }

            return fft_impl::CUFFT;
        }

        if (n <= 250000 && mkl) {
            return fft_impl::MKL;
        }

        return fft_impl::CUFFT;
    } else if (mkl) {
        if (is_power_of_two(n) && n <= 64) {
            return fft_impl::STD;
        }

        return fft_impl::MKL;
    } else {
        return fft_impl::STD;
    }
}

/*!
 * \brief Select a Many-1D FFT implementation based on the operation size
 * \param batch The number of operations
 * \param n The size of the operation
 * \return The implementation to use
 */
inline cpp14_constexpr fft_impl select_fft1_many_impl(const std::size_t batch, const std::size_t n) {
    cpp_unused(batch);

    //Note since these boolean will be known at compile time, the conditions will be a lot simplified
    constexpr const bool mkl   = is_mkl_enabled::value;
    constexpr const bool cufft = is_cufft_enabled::value;

    //Note: more testing would probably improve this selection

    if (cufft) {
        if (n <= 250000 && mkl) {
            return fft_impl::MKL;
        }

        return fft_impl::CUFFT;
    } else if (mkl) {
        return fft_impl::MKL;
    } else {
        return fft_impl::STD;
    }
}

/*!
 * \brief Select a 1D IFFT implementation based on the operation size
 * \param n The size of the operation
 * \return The implementation to use
 */
inline cpp14_constexpr fft_impl select_ifft1_impl(const std::size_t n) {
    //Note since these boolean will be known at compile time, the conditions will be a lot simplified
    constexpr const bool mkl   = is_mkl_enabled::value;
    constexpr const bool cufft = is_cufft_enabled::value;

    if (cufft) {
        if (is_power_of_two(n)) {
            if (n <= 1024) {
                if (mkl) {
                    return fft_impl::MKL;
                } else {
                    return fft_impl::STD;
                }
            } else if (n <= 262144 && mkl) {
                return fft_impl::MKL;
            }

            return fft_impl::CUFFT;
        }

        if (n <= 250000 && mkl) {
            return fft_impl::MKL;
        }

        return fft_impl::CUFFT;
    } else if (mkl) {
        return fft_impl::MKL;
    } else {
        return fft_impl::STD;
    }
}

/*!
 * \brief Select a 2D FFT implementation based on the operation size
 * \param n1 The first dimension of the operation
 * \param n2 The second dimension of the operation
 * \return The implementation to use
 */
inline cpp14_constexpr fft_impl select_fft2_impl(const std::size_t n1, std::size_t n2) {
    //Note since these boolean will be known at compile time, the conditions will be a lot simplified
    constexpr const bool mkl   = is_mkl_enabled::value;
    constexpr const bool cufft = is_cufft_enabled::value;

    if (cufft) {
        if (is_power_of_two(n1) && is_power_of_two(n2)) {
            if (n1 * n2 < 150 * 150) {
                if (mkl) {
                    return fft_impl::MKL;
                } else {
                    return fft_impl::STD;
                }
            } else if (n1 * n2 <= 768 * 768 && mkl) {
                return fft_impl::MKL;
            }

            return fft_impl::CUFFT;
        }

        if (n1 * n2 <= 768 * 768 && mkl) {
            return fft_impl::MKL;
        }

        return fft_impl::CUFFT;
    } else if (mkl) {
        return fft_impl::MKL;
    } else {
        return fft_impl::STD;
    }
}

/*!
 * \brief Select a Many-2D FFT implementation based on the operation size
 * \param batch The number of operations
 * \param n1 The first dimension of the operation
 * \param n2 The second dimension of the operation
 * \return The implementation to use
 */
inline cpp14_constexpr fft_impl select_fft2_many_impl(const std::size_t batch, const std::size_t n1, const std::size_t n2) {
    cpp_unused(batch);

    //Note since these boolean will be known at compile time, the conditions will be a lot simplified
    constexpr const bool mkl   = is_mkl_enabled::value;
    constexpr const bool cufft = is_cufft_enabled::value;

    //Note: more testing would probably improve this selection

    if (cufft) {
        if (n1 * n2 <= 768 * 768 && mkl) {
            return fft_impl::MKL;
        }

        return fft_impl::CUFFT;
    } else if (mkl) {
        return fft_impl::MKL;
    } else {
        return fft_impl::STD;
    }
}

template <typename A, typename C>
struct fft1_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_fft1_impl(etl::size(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::fft1(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::fft1(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::fft1(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct ifft1_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_ifft1_impl(etl::size(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::ifft1(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::ifft1(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::ifft1(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct ifft1_real_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_ifft1_impl(etl::size(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::ifft1_real(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::ifft1_real(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::ifft1_real(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct fft2_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_fft2_impl(etl::dim<0>(c), etl::dim<1>(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::fft2(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::fft2(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::fft2(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct ifft2_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_fft2_impl(etl::dim<0>(c), etl::dim<1>(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::ifft2(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::ifft2(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::ifft2(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct ifft2_real_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_fft2_impl(etl::dim<0>(c), etl::dim<1>(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::ifft2_real(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::ifft2_real(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::ifft2_real(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct fft1_many_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_fft1_many_impl(etl::dim<0>(c), etl::dim<1>(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::fft1_many(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::fft1_many(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::fft1_many(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename C>
struct fft2_many_impl {
    template <typename AA, typename CC>
    static void apply(AA&& a, CC&& c) {
        fft_impl impl = select_fft2_many_impl(etl::dim<0>(c), etl::dim<1>(c), etl::dim<2>(c));

        if (impl == fft_impl::STD) {
            etl::impl::standard::fft2_many(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::MKL) {
            etl::impl::blas::fft2_many(std::forward<AA>(a), std::forward<CC>(c));
        } else if (impl == fft_impl::CUFFT) {
            etl::impl::cufft::fft2_many(std::forward<AA>(a), std::forward<CC>(c));
        }
    }
};

template <typename A, typename B, typename C, typename Enable = void>
struct fft_conv1_full_impl {
    template <typename AA, typename BB, typename CC>
    static void apply(AA&& a, BB&& b, CC&& c) {
        if(is_cufft_enabled::value){
            etl::impl::cufft::fft1_convolve(std::forward<AA>(a), std::forward<BB>(b), std::forward<CC>(c));
        } else if(is_mkl_enabled::value){
            etl::impl::blas::fft1_convolve(std::forward<AA>(a), std::forward<BB>(b), std::forward<CC>(c));
        } else {
            etl::impl::standard::fft1_convolve(std::forward<AA>(a), std::forward<BB>(b), std::forward<CC>(c));
        }
    }
};

template <typename A, typename B, typename C, typename Enable = void>
struct fft_conv2_full_impl {
    template <typename AA, typename BB, typename CC>
    static void apply(AA&& a, BB&& b, CC&& c) {
        if(is_cufft_enabled::value){
            etl::impl::cufft::fft2_convolve(std::forward<AA>(a), std::forward<BB>(b), std::forward<CC>(c));
        } else if(is_mkl_enabled::value){
            etl::impl::blas::fft2_convolve(std::forward<AA>(a), std::forward<BB>(b), std::forward<CC>(c));
        } else {
            etl::impl::standard::fft2_convolve(std::forward<AA>(a), std::forward<BB>(b), std::forward<CC>(c));
        }
    }
};

} //end of namespace detail

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


<commit_before>#pragma once

#include <cstddef>
#include <cstdint>
#include <string_view>
#include <vector>

#include <boo/graphicsdev/IGraphicsDataFactory.hpp>

#include "hecl.hpp"
#include "../extern/boo/xxhash/xxhash.h"

namespace hecl::Backend {
struct ExtensionSlot;
using namespace std::literals;

enum class TexCoordSource : uint8_t {
  Invalid = 0xff,
  Position = 0,
  Normal = 1,
  Tex0 = 2,
  Tex1 = 3,
  Tex2 = 4,
  Tex3 = 5,
  Tex4 = 6,
  Tex5 = 7,
  Tex6 = 8,
  Tex7 = 9,
};

enum class BlendFactor : uint8_t {
  Zero,
  One,
  SrcColor,
  InvSrcColor,
  DstColor,
  InvDstColor,
  SrcAlpha,
  InvSrcAlpha,
  DstAlpha,
  InvDstAlpha,
  SrcColor1,
  InvSrcColor1,
  Original = 0xff
};

constexpr std::string_view BlendFactorToDefine(BlendFactor factor, BlendFactor defaultFactor) {
  switch (factor) {
  case BlendFactor::Zero:
    return "ZERO"sv;
  case BlendFactor::One:
    return "ONE"sv;
  case BlendFactor::SrcColor:
    return "SRCCOLOR"sv;
  case BlendFactor::InvSrcColor:
    return "INVSRCCOLOR"sv;
  case BlendFactor::DstColor:
    return "DSTCOLOR"sv;
  case BlendFactor::InvDstColor:
    return "INVDSTCOLOR"sv;
  case BlendFactor::SrcAlpha:
    return "SRCALPHA"sv;
  case BlendFactor::InvSrcAlpha:
    return "INVSRCALPHA"sv;
  case BlendFactor::DstAlpha:
    return "DSTALPHA"sv;
  case BlendFactor::InvDstAlpha:
    return "INVDSTALPHA"sv;
  case BlendFactor::SrcColor1:
    return "SRCCOLOR1"sv;
  case BlendFactor::InvSrcColor1:
    return "INVSRCCOLOR1"sv;
  default:
    return BlendFactorToDefine(defaultFactor, BlendFactor::Zero);
  }
}

enum class ZTest : uint8_t { None, LEqual, Greater, Equal, GEqual, Original = 0xff };

enum class CullMode : uint8_t { None, Backface, Frontface, Original = 0xff };

struct TextureInfo {
  TexCoordSource src;
  uint8_t mtxIdx;
  bool normalize;
};

enum class ReflectionType { None, Simple, Indirect };

/**
 * @brief Hash subclass for identifying shaders and their metadata
 */
class ShaderTag : public Hash {
  union {
    uint64_t m_meta = 0;
    struct {
      uint8_t m_colorCount;
      uint8_t m_uvCount;
      uint8_t m_weightCount;
      uint8_t m_skinSlotCount;
      uint8_t m_primitiveType;
      uint8_t m_reflectionType;
      bool m_depthTest : 1;
      bool m_depthWrite : 1;
      bool m_backfaceCulling : 1;
      bool m_alphaTest : 1;
    };
  };

public:
  ShaderTag() = default;
  ShaderTag(std::string_view source, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt,
            Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling,
            bool alphaTest)
  : Hash(source) {
    m_colorCount = c;
    m_uvCount = u;
    m_weightCount = w;
    m_skinSlotCount = s;
    m_primitiveType = uint8_t(pt);
    m_reflectionType = uint8_t(reflectionType);
    m_depthTest = depthTest;
    m_depthWrite = depthWrite;
    m_backfaceCulling = backfaceCulling;
    m_alphaTest = alphaTest;
    hash ^= m_meta;
  }
  ShaderTag(uint64_t hashin, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt,
            Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling,
            bool alphaTest)
  : Hash(hashin) {
    m_colorCount = c;
    m_uvCount = u;
    m_weightCount = w;
    m_skinSlotCount = s;
    m_primitiveType = uint8_t(pt);
    m_reflectionType = uint8_t(reflectionType);
    m_depthTest = depthTest;
    m_depthWrite = depthWrite;
    m_backfaceCulling = backfaceCulling;
    m_alphaTest = alphaTest;
    hash ^= m_meta;
  }
  ShaderTag(uint64_t comphashin, uint64_t meta) : Hash(comphashin), m_meta(meta) {}
  ShaderTag(const ShaderTag& other) : Hash(other), m_meta(other.m_meta) {}
  uint8_t getColorCount() const { return m_colorCount; }
  uint8_t getUvCount() const { return m_uvCount; }
  uint8_t getWeightCount() const { return m_weightCount; }
  uint8_t getSkinSlotCount() const { return m_skinSlotCount; }
  boo::Primitive getPrimType() const { return boo::Primitive(m_primitiveType); }
  Backend::ReflectionType getReflectionType() const { return Backend::ReflectionType(m_reflectionType); }
  bool getDepthTest() const { return m_depthTest; }
  bool getDepthWrite() const { return m_depthWrite; }
  bool getBackfaceCulling() const { return m_backfaceCulling; }
  bool getAlphaTest() const { return m_alphaTest; }
  uint64_t getMetaData() const { return m_meta; }

  std::vector<boo::VertexElementDescriptor> vertexFormat() const {
    std::vector<boo::VertexElementDescriptor> ret;
    size_t elemCount = 2 + m_colorCount + m_uvCount + m_weightCount;
    ret.resize(elemCount);

    ret[0].semantic = boo::VertexSemantic::Position3;
    ret[1].semantic = boo::VertexSemantic::Normal3;
    size_t e = 2;

    for (size_t i = 0; i < m_colorCount; ++i, ++e) {
      ret[e].semantic = boo::VertexSemantic::ColorUNorm;
      ret[e].semanticIdx = i;
    }

    for (size_t i = 0; i < m_uvCount; ++i, ++e) {
      ret[e].semantic = boo::VertexSemantic::UV2;
      ret[e].semanticIdx = i;
    }

    for (size_t i = 0; i < m_weightCount; ++i, ++e) {
      ret[e].semantic = boo::VertexSemantic::Weight;
      ret[e].semanticIdx = i;
    }

    return ret;
  }

  boo::AdditionalPipelineInfo additionalInfo(const ExtensionSlot& ext,
                                             std::pair<BlendFactor, BlendFactor> blendFactors) const;
};

struct Function {
  std::string_view m_source;
  std::string_view m_entry;
  Function() = default;
  Function(std::string_view source, std::string_view entry) : m_source(source), m_entry(entry) {}
};

struct ExtensionSlot {
  const char* shaderMacro;
  size_t texCount = 0;
  const Backend::TextureInfo* texs = nullptr;
  Backend::BlendFactor srcFactor = Backend::BlendFactor::Original;
  Backend::BlendFactor dstFactor = Backend::BlendFactor::Original;
  Backend::ZTest depthTest = Backend::ZTest::Original;
  Backend::CullMode cullMode = Backend::CullMode::Backface;
  bool noDepthWrite = false;
  bool noColorWrite = false;
  bool noAlphaWrite = false;
  bool noAlphaOverwrite = false;
  bool noReflection = false;
  bool forceAlphaTest = false;
  bool diffuseOnly = false;

  ExtensionSlot(size_t texCount = 0,
                const Backend::TextureInfo* texs = nullptr,
                Backend::BlendFactor srcFactor = Backend::BlendFactor::Original,
                Backend::BlendFactor dstFactor = Backend::BlendFactor::Original,
                Backend::ZTest depthTest = Backend::ZTest::Original,
                Backend::CullMode cullMode = Backend::CullMode::Backface, bool noDepthWrite = false,
                bool noColorWrite = false, bool noAlphaWrite = false, bool noAlphaOverwrite = false,
                bool noReflection = false, bool forceAlphaTest = false, bool diffuseOnly = false)
  : texCount(texCount)
  , texs(texs)
  , srcFactor(srcFactor)
  , dstFactor(dstFactor)
  , depthTest(depthTest)
  , cullMode(cullMode)
  , noDepthWrite(noDepthWrite)
  , noColorWrite(noColorWrite)
  , noAlphaWrite(noAlphaWrite)
  , noAlphaOverwrite(noAlphaOverwrite)
  , noReflection(noReflection)
  , forceAlphaTest(forceAlphaTest)
  , diffuseOnly(diffuseOnly) {}

  mutable uint64_t m_hash = 0;
  void calculateHash() const {
    XXH64_state_t st;
    XXH64_reset(&st, 0);
    XXH64_update(&st, shaderMacro, strlen(shaderMacro));
    for (size_t i = 0; i < texCount; ++i) {
      const Backend::TextureInfo& tinfo = texs[i];
      XXH64_update(&st, &tinfo, sizeof(tinfo));
    }
    XXH64_update(&st, &srcFactor, offsetof(ExtensionSlot, m_hash) - offsetof(ExtensionSlot, srcFactor));
    m_hash = XXH64_digest(&st);
  }
  uint64_t hash() const {
    if (m_hash == 0)
      calculateHash();
    return m_hash;
  }
};

inline boo::AdditionalPipelineInfo ShaderTag::additionalInfo(const ExtensionSlot& ext,
                                                             std::pair<BlendFactor, BlendFactor> blendFactors) const {
  boo::ZTest zTest;
  switch (ext.depthTest) {
  case hecl::Backend::ZTest::Original:
  default:
    zTest = getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None;
    break;
  case hecl::Backend::ZTest::None:
    zTest = boo::ZTest::None;
    break;
  case hecl::Backend::ZTest::LEqual:
    zTest = boo::ZTest::LEqual;
    break;
  case hecl::Backend::ZTest::Greater:
    zTest = boo::ZTest::Greater;
    break;
  case hecl::Backend::ZTest::Equal:
    zTest = boo::ZTest::Equal;
    break;
  case hecl::Backend::ZTest::GEqual:
    zTest = boo::ZTest::GEqual;
    break;
  }

  BlendFactor srcFactor = m_alphaTest ? BlendFactor::One : blendFactors.first;
  BlendFactor dstFactor = m_alphaTest ? BlendFactor::Zero : blendFactors.second;
  return {boo::BlendFactor((ext.srcFactor == BlendFactor::Original) ? srcFactor : ext.srcFactor),
          boo::BlendFactor((ext.dstFactor == BlendFactor::Original) ? dstFactor : ext.dstFactor),
          getPrimType(),
          zTest,
          ext.noDepthWrite ? false : getDepthWrite(),
          !ext.noColorWrite,
          !ext.noAlphaWrite,
          (ext.cullMode == hecl::Backend::CullMode::Original)
              ? (getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None)
              : boo::CullMode(ext.cullMode),
          !ext.noAlphaOverwrite};
}

} // namespace hecl::Backend

namespace std {
template <>
struct hash<hecl::Backend::ShaderTag> {
  size_t operator()(const hecl::Backend::ShaderTag& val) const noexcept { return val.valSizeT(); }
};
} // namespace std
<commit_msg>Backend: Make ExtensionSlot's constructor constexpr<commit_after>#pragma once

#include <cstddef>
#include <cstdint>
#include <string_view>
#include <vector>

#include <boo/graphicsdev/IGraphicsDataFactory.hpp>

#include "hecl.hpp"
#include "../extern/boo/xxhash/xxhash.h"

namespace hecl::Backend {
struct ExtensionSlot;
using namespace std::literals;

enum class TexCoordSource : uint8_t {
  Invalid = 0xff,
  Position = 0,
  Normal = 1,
  Tex0 = 2,
  Tex1 = 3,
  Tex2 = 4,
  Tex3 = 5,
  Tex4 = 6,
  Tex5 = 7,
  Tex6 = 8,
  Tex7 = 9,
};

enum class BlendFactor : uint8_t {
  Zero,
  One,
  SrcColor,
  InvSrcColor,
  DstColor,
  InvDstColor,
  SrcAlpha,
  InvSrcAlpha,
  DstAlpha,
  InvDstAlpha,
  SrcColor1,
  InvSrcColor1,
  Original = 0xff
};

constexpr std::string_view BlendFactorToDefine(BlendFactor factor, BlendFactor defaultFactor) {
  switch (factor) {
  case BlendFactor::Zero:
    return "ZERO"sv;
  case BlendFactor::One:
    return "ONE"sv;
  case BlendFactor::SrcColor:
    return "SRCCOLOR"sv;
  case BlendFactor::InvSrcColor:
    return "INVSRCCOLOR"sv;
  case BlendFactor::DstColor:
    return "DSTCOLOR"sv;
  case BlendFactor::InvDstColor:
    return "INVDSTCOLOR"sv;
  case BlendFactor::SrcAlpha:
    return "SRCALPHA"sv;
  case BlendFactor::InvSrcAlpha:
    return "INVSRCALPHA"sv;
  case BlendFactor::DstAlpha:
    return "DSTALPHA"sv;
  case BlendFactor::InvDstAlpha:
    return "INVDSTALPHA"sv;
  case BlendFactor::SrcColor1:
    return "SRCCOLOR1"sv;
  case BlendFactor::InvSrcColor1:
    return "INVSRCCOLOR1"sv;
  default:
    return BlendFactorToDefine(defaultFactor, BlendFactor::Zero);
  }
}

enum class ZTest : uint8_t { None, LEqual, Greater, Equal, GEqual, Original = 0xff };

enum class CullMode : uint8_t { None, Backface, Frontface, Original = 0xff };

struct TextureInfo {
  TexCoordSource src;
  uint8_t mtxIdx;
  bool normalize;
};

enum class ReflectionType { None, Simple, Indirect };

/**
 * @brief Hash subclass for identifying shaders and their metadata
 */
class ShaderTag : public Hash {
  union {
    uint64_t m_meta = 0;
    struct {
      uint8_t m_colorCount;
      uint8_t m_uvCount;
      uint8_t m_weightCount;
      uint8_t m_skinSlotCount;
      uint8_t m_primitiveType;
      uint8_t m_reflectionType;
      bool m_depthTest : 1;
      bool m_depthWrite : 1;
      bool m_backfaceCulling : 1;
      bool m_alphaTest : 1;
    };
  };

public:
  ShaderTag() = default;
  ShaderTag(std::string_view source, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt,
            Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling,
            bool alphaTest)
  : Hash(source) {
    m_colorCount = c;
    m_uvCount = u;
    m_weightCount = w;
    m_skinSlotCount = s;
    m_primitiveType = uint8_t(pt);
    m_reflectionType = uint8_t(reflectionType);
    m_depthTest = depthTest;
    m_depthWrite = depthWrite;
    m_backfaceCulling = backfaceCulling;
    m_alphaTest = alphaTest;
    hash ^= m_meta;
  }
  ShaderTag(uint64_t hashin, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt,
            Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling,
            bool alphaTest)
  : Hash(hashin) {
    m_colorCount = c;
    m_uvCount = u;
    m_weightCount = w;
    m_skinSlotCount = s;
    m_primitiveType = uint8_t(pt);
    m_reflectionType = uint8_t(reflectionType);
    m_depthTest = depthTest;
    m_depthWrite = depthWrite;
    m_backfaceCulling = backfaceCulling;
    m_alphaTest = alphaTest;
    hash ^= m_meta;
  }
  ShaderTag(uint64_t comphashin, uint64_t meta) : Hash(comphashin), m_meta(meta) {}
  ShaderTag(const ShaderTag& other) : Hash(other), m_meta(other.m_meta) {}
  uint8_t getColorCount() const { return m_colorCount; }
  uint8_t getUvCount() const { return m_uvCount; }
  uint8_t getWeightCount() const { return m_weightCount; }
  uint8_t getSkinSlotCount() const { return m_skinSlotCount; }
  boo::Primitive getPrimType() const { return boo::Primitive(m_primitiveType); }
  Backend::ReflectionType getReflectionType() const { return Backend::ReflectionType(m_reflectionType); }
  bool getDepthTest() const { return m_depthTest; }
  bool getDepthWrite() const { return m_depthWrite; }
  bool getBackfaceCulling() const { return m_backfaceCulling; }
  bool getAlphaTest() const { return m_alphaTest; }
  uint64_t getMetaData() const { return m_meta; }

  std::vector<boo::VertexElementDescriptor> vertexFormat() const {
    std::vector<boo::VertexElementDescriptor> ret;
    size_t elemCount = 2 + m_colorCount + m_uvCount + m_weightCount;
    ret.resize(elemCount);

    ret[0].semantic = boo::VertexSemantic::Position3;
    ret[1].semantic = boo::VertexSemantic::Normal3;
    size_t e = 2;

    for (size_t i = 0; i < m_colorCount; ++i, ++e) {
      ret[e].semantic = boo::VertexSemantic::ColorUNorm;
      ret[e].semanticIdx = i;
    }

    for (size_t i = 0; i < m_uvCount; ++i, ++e) {
      ret[e].semantic = boo::VertexSemantic::UV2;
      ret[e].semanticIdx = i;
    }

    for (size_t i = 0; i < m_weightCount; ++i, ++e) {
      ret[e].semantic = boo::VertexSemantic::Weight;
      ret[e].semanticIdx = i;
    }

    return ret;
  }

  boo::AdditionalPipelineInfo additionalInfo(const ExtensionSlot& ext,
                                             std::pair<BlendFactor, BlendFactor> blendFactors) const;
};

struct Function {
  std::string_view m_source;
  std::string_view m_entry;
  Function() = default;
  Function(std::string_view source, std::string_view entry) : m_source(source), m_entry(entry) {}
};

struct ExtensionSlot {
  const char* shaderMacro = nullptr;
  size_t texCount = 0;
  const Backend::TextureInfo* texs = nullptr;
  Backend::BlendFactor srcFactor = Backend::BlendFactor::Original;
  Backend::BlendFactor dstFactor = Backend::BlendFactor::Original;
  Backend::ZTest depthTest = Backend::ZTest::Original;
  Backend::CullMode cullMode = Backend::CullMode::Backface;
  bool noDepthWrite = false;
  bool noColorWrite = false;
  bool noAlphaWrite = false;
  bool noAlphaOverwrite = false;
  bool noReflection = false;
  bool forceAlphaTest = false;
  bool diffuseOnly = false;

  constexpr ExtensionSlot(size_t texCount = 0, const Backend::TextureInfo* texs = nullptr,
                          Backend::BlendFactor srcFactor = Backend::BlendFactor::Original,
                          Backend::BlendFactor dstFactor = Backend::BlendFactor::Original,
                          Backend::ZTest depthTest = Backend::ZTest::Original,
                          Backend::CullMode cullMode = Backend::CullMode::Backface, bool noDepthWrite = false,
                          bool noColorWrite = false, bool noAlphaWrite = false, bool noAlphaOverwrite = false,
                          bool noReflection = false, bool forceAlphaTest = false, bool diffuseOnly = false) noexcept
  : texCount(texCount)
  , texs(texs)
  , srcFactor(srcFactor)
  , dstFactor(dstFactor)
  , depthTest(depthTest)
  , cullMode(cullMode)
  , noDepthWrite(noDepthWrite)
  , noColorWrite(noColorWrite)
  , noAlphaWrite(noAlphaWrite)
  , noAlphaOverwrite(noAlphaOverwrite)
  , noReflection(noReflection)
  , forceAlphaTest(forceAlphaTest)
  , diffuseOnly(diffuseOnly) {}

  mutable uint64_t m_hash = 0;
  void calculateHash() const {
    XXH64_state_t st;
    XXH64_reset(&st, 0);
    XXH64_update(&st, shaderMacro, strlen(shaderMacro));
    for (size_t i = 0; i < texCount; ++i) {
      const Backend::TextureInfo& tinfo = texs[i];
      XXH64_update(&st, &tinfo, sizeof(tinfo));
    }
    XXH64_update(&st, &srcFactor, offsetof(ExtensionSlot, m_hash) - offsetof(ExtensionSlot, srcFactor));
    m_hash = XXH64_digest(&st);
  }
  uint64_t hash() const {
    if (m_hash == 0)
      calculateHash();
    return m_hash;
  }
};

inline boo::AdditionalPipelineInfo ShaderTag::additionalInfo(const ExtensionSlot& ext,
                                                             std::pair<BlendFactor, BlendFactor> blendFactors) const {
  boo::ZTest zTest;
  switch (ext.depthTest) {
  case hecl::Backend::ZTest::Original:
  default:
    zTest = getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None;
    break;
  case hecl::Backend::ZTest::None:
    zTest = boo::ZTest::None;
    break;
  case hecl::Backend::ZTest::LEqual:
    zTest = boo::ZTest::LEqual;
    break;
  case hecl::Backend::ZTest::Greater:
    zTest = boo::ZTest::Greater;
    break;
  case hecl::Backend::ZTest::Equal:
    zTest = boo::ZTest::Equal;
    break;
  case hecl::Backend::ZTest::GEqual:
    zTest = boo::ZTest::GEqual;
    break;
  }

  BlendFactor srcFactor = m_alphaTest ? BlendFactor::One : blendFactors.first;
  BlendFactor dstFactor = m_alphaTest ? BlendFactor::Zero : blendFactors.second;
  return {boo::BlendFactor((ext.srcFactor == BlendFactor::Original) ? srcFactor : ext.srcFactor),
          boo::BlendFactor((ext.dstFactor == BlendFactor::Original) ? dstFactor : ext.dstFactor),
          getPrimType(),
          zTest,
          ext.noDepthWrite ? false : getDepthWrite(),
          !ext.noColorWrite,
          !ext.noAlphaWrite,
          (ext.cullMode == hecl::Backend::CullMode::Original)
              ? (getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None)
              : boo::CullMode(ext.cullMode),
          !ext.noAlphaOverwrite};
}

} // namespace hecl::Backend

namespace std {
template <>
struct hash<hecl::Backend::ShaderTag> {
  size_t operator()(const hecl::Backend::ShaderTag& val) const noexcept { return val.valSizeT(); }
};
} // namespace std
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
//
// 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.

#include "build_log.h"

#include "util.h"
#include "test.h"

#include <sys/stat.h>
#ifdef _WIN32
#include <fcntl.h>
#include <share.h>
#else
#include <sys/types.h>
#include <unistd.h>
#endif
#include <cassert>

namespace {

const char kTestFilename[] = "BuildLogTest-tempfile";

struct BuildLogTest : public StateTestWithBuiltinRules, public BuildLogUser {
  virtual void SetUp() {
    // In case a crashing test left a stale file behind.
    unlink(kTestFilename);
  }
  virtual void TearDown() {
    unlink(kTestFilename);
  }
  virtual bool IsPathDead(StringPiece s) const { return false; }
};

TEST_F(BuildLogTest, WriteRead) {
  AssertParse(&state_,
"build out: cat mid\n"
"build mid: cat in\n");

  BuildLog log1;
  string err;
  EXPECT_TRUE(log1.OpenForWrite(kTestFilename, *this, &err));
  ASSERT_EQ("", err);
  log1.RecordCommand(state_.edges_[0], 15, 18);
  log1.RecordCommand(state_.edges_[1], 20, 25);
  log1.Close();

  BuildLog log2;
  EXPECT_TRUE(log2.Load(kTestFilename, &err));
  ASSERT_EQ("", err);

  ASSERT_EQ(2u, log1.entries().size());
  ASSERT_EQ(2u, log2.entries().size());
  BuildLog::LogEntry* e1 = log1.LookupByOutput("out");
  ASSERT_TRUE(e1);
  BuildLog::LogEntry* e2 = log2.LookupByOutput("out");
  ASSERT_TRUE(e2);
  ASSERT_TRUE(*e1 == *e2);
  ASSERT_EQ(15, e1->start_time);
  ASSERT_EQ("out", e1->output);
}

TEST_F(BuildLogTest, FirstWriteAddsSignature) {
  const char kExpectedVersion[] = "# ninja log vX\n";
  const size_t kVersionPos = strlen(kExpectedVersion) - 2;  // Points at 'X'.

  BuildLog log;
  string contents, err;

  EXPECT_TRUE(log.OpenForWrite(kTestFilename, *this, &err));
  ASSERT_EQ("", err);
  log.Close();

  ASSERT_EQ(0, ReadFile(kTestFilename, &contents, &err));
  ASSERT_EQ("", err);
  if (contents.size() >= kVersionPos)
    contents[kVersionPos] = 'X';
  EXPECT_EQ(kExpectedVersion, contents);

  // Opening the file anew shouldn't add a second version string.
  EXPECT_TRUE(log.OpenForWrite(kTestFilename, *this, &err));
  ASSERT_EQ("", err);
  log.Close();

  contents.clear();
  ASSERT_EQ(0, ReadFile(kTestFilename, &contents, &err));
  ASSERT_EQ("", err);
  if (contents.size() >= kVersionPos)
    contents[kVersionPos] = 'X';
  EXPECT_EQ(kExpectedVersion, contents);
}

TEST_F(BuildLogTest, DoubleEntry) {
  FILE* f = fopen(kTestFilename, "wb");
  fprintf(f, "# ninja log v4\n");
  fprintf(f, "0\t1\t2\tout\tcommand abc\n");
  fprintf(f, "3\t4\t5\tout\tcommand def\n");
  fclose(f);

  string err;
  BuildLog log;
  EXPECT_TRUE(log.Load(kTestFilename, &err));
  ASSERT_EQ("", err);

  BuildLog::LogEntry* e = log.LookupByOutput("out");
  ASSERT_TRUE(e);
  ASSERT_NO_FATAL_FAILURE(AssertHash("command def", e->command_hash));
}

TEST_F(BuildLogTest, Truncate) {
  AssertParse(&state_,
"build out: cat mid\n"
"build mid: cat in\n");

  {
    BuildLog log1;
    string err;
    EXPECT_TRUE(log1.OpenForWrite(kTestFilename, *this, &err));
    ASSERT_EQ("", err);
    log1.RecordCommand(state_.edges_[0], 15, 18);
    log1.RecordCommand(state_.edges_[1], 20, 25);
    log1.Close();
  }

  struct stat statbuf;
  ASSERT_EQ(0, stat(kTestFilename, &statbuf));
  ASSERT_GT(statbuf.st_size, 0);

  // For all possible truncations of the input file, assert that we don't
  // crash when parsing.
  for (off_t size = statbuf.st_size; size > 0; --size) {
    BuildLog log2;
    string err;
    EXPECT_TRUE(log2.OpenForWrite(kTestFilename, *this, &err));
    ASSERT_EQ("", err);
    log2.RecordCommand(state_.edges_[0], 15, 18);
    log2.RecordCommand(state_.edges_[1], 20, 25);
    log2.Close();

    ASSERT_TRUE(Truncate(kTestFilename, size, &err));

    BuildLog log3;
    err.clear();
    ASSERT_TRUE(log3.Load(kTestFilename, &err) == LOAD_SUCCESS || !err.empty());
  }
}

TEST_F(BuildLogTest, ObsoleteOldVersion) {
  FILE* f = fopen(kTestFilename, "wb");
  fprintf(f, "# ninja log v3\n");
  fprintf(f, "123 456 0 out command\n");
  fclose(f);

  string err;
  BuildLog log;
  EXPECT_TRUE(log.Load(kTestFilename, &err));
  ASSERT_NE(err.find("version"), string::npos);
}

TEST_F(BuildLogTest, SpacesInOutputV4) {
  FILE* f = fopen(kTestFilename, "wb");
  fprintf(f, "# ninja log v4\n");
  fprintf(f, "123\t456\t456\tout with space\tcommand\n");
  fclose(f);

  string err;
  BuildLog log;
  EXPECT_TRUE(log.Load(kTestFilename, &err));
  ASSERT_EQ("", err);

  BuildLog::LogEntry* e = log.LookupByOutput("out with space");
  ASSERT_TRUE(e);
  ASSERT_EQ(123, e->start_time);
  ASSERT_EQ(456, e->end_time);
  ASSERT_EQ(456, e->mtime);
  ASSERT_NO_FATAL_FAILURE(AssertHash("command", e->command_hash));
}

TEST_F(BuildLogTest, DuplicateVersionHeader) {
  // Old versions of ninja accidentally wrote multiple version headers to the
  // build log on Windows. This shouldn't crash, and the second version header
  // should be ignored.
  FILE* f = fopen(kTestFilename, "wb");
  fprintf(f, "# ninja log v4\n");
  fprintf(f, "123\t456\t456\tout\tcommand\n");
  fprintf(f, "# ninja log v4\n");
  fprintf(f, "456\t789\t789\tout2\tcommand2\n");
  fclose(f);

  string err;
  BuildLog log;
  EXPECT_TRUE(log.Load(kTestFilename, &err));
  ASSERT_EQ("", err);

  BuildLog::LogEntry* e = log.LookupByOutput("out");
  ASSERT_TRUE(e);
  ASSERT_EQ(123, e->start_time);
  ASSERT_EQ(456, e->end_time);
  ASSERT_EQ(456, e->mtime);
  ASSERT_NO_FATAL_FAILURE(AssertHash("command", e->command_hash));

  e = log.LookupByOutput("out2");
  ASSERT_TRUE(e);
  ASSERT_EQ(456, e->start_time);
  ASSERT_EQ(789, e->end_time);
  ASSERT_EQ(789, e->mtime);
  ASSERT_NO_FATAL_FAILURE(AssertHash("command2", e->command_hash));
}

struct TestDiskInterface : public DiskInterface {
  virtual TimeStamp Stat(const string& path, string* err) const {
    return 4;
  }
  virtual bool WriteFile(const string& path, const string& contents) {
    assert(false);
    return true;
  }
  virtual bool MakeDir(const string& path) {
    assert(false);
    return false;
  }
  virtual Status ReadFile(const string& path, string* contents, string* err) {
    assert(false);
    return NotFound;
  }
  virtual int RemoveFile(const string& path) {
    assert(false);
    return 0;
  }
};

TEST_F(BuildLogTest, Restat) {
  FILE* f = fopen(kTestFilename, "wb");
  fprintf(f, "# ninja log v4\n"
             "1\t2\t3\tout\tcommand\n");
  fclose(f);
  std::string err;
  BuildLog log;
  EXPECT_TRUE(log.Load(kTestFilename, &err));
  ASSERT_EQ("", err);
  BuildLog::LogEntry* e = log.LookupByOutput("out");
  ASSERT_EQ(3, e->mtime);

  TestDiskInterface testDiskInterface;
  char out2[] = { 'o', 'u', 't', '2' };
  char* filter2[] = { out2 };
  EXPECT_TRUE(log.Restat(kTestFilename, testDiskInterface, 1, filter2, &err));
  ASSERT_EQ("", err);
  e = log.LookupByOutput("out");
  ASSERT_EQ(3, e->mtime); // unchanged, since the filter doesn't match

  EXPECT_TRUE(log.Restat(kTestFilename, testDiskInterface, 0, NULL, &err));
  ASSERT_EQ("", err);
  e = log.LookupByOutput("out");
  ASSERT_EQ(4, e->mtime);
}

TEST_F(BuildLogTest, VeryLongInputLine) {
  // Ninja's build log buffer is currently 256kB. Lines longer than that are
  // silently ignored, but don't affect parsing of other lines.
  FILE* f = fopen(kTestFilename, "wb");
  fprintf(f, "# ninja log v4\n");
  fprintf(f, "123\t456\t456\tout\tcommand start");
  for (size_t i = 0; i < (512 << 10) / strlen(" more_command"); ++i)
    fputs(" more_command", f);
  fprintf(f, "\n");
  fprintf(f, "456\t789\t789\tout2\tcommand2\n");
  fclose(f);

  string err;
  BuildLog log;
  EXPECT_TRUE(log.Load(kTestFilename, &err));
  ASSERT_EQ("", err);

  BuildLog::LogEntry* e = log.LookupByOutput("out");
  ASSERT_EQ(NULL, e);

  e = log.LookupByOutput("out2");
  ASSERT_TRUE(e);
  ASSERT_EQ(456, e->start_time);
  ASSERT_EQ(789, e->end_time);
  ASSERT_EQ(789, e->mtime);
  ASSERT_NO_FATAL_FAILURE(AssertHash("command2", e->command_hash));
}

TEST_F(BuildLogTest, MultiTargetEdge) {
  AssertParse(&state_,
"build out out.d: cat\n");

  BuildLog log;
  log.RecordCommand(state_.edges_[0], 21, 22);

  ASSERT_EQ(2u, log.entries().size());
  BuildLog::LogEntry* e1 = log.LookupByOutput("out");
  ASSERT_TRUE(e1);
  BuildLog::LogEntry* e2 = log.LookupByOutput("out.d");
  ASSERT_TRUE(e2);
  ASSERT_EQ("out", e1->output);
  ASSERT_EQ("out.d", e2->output);
  ASSERT_EQ(21, e1->start_time);
  ASSERT_EQ(21, e2->start_time);
  ASSERT_EQ(22, e2->end_time);
  ASSERT_EQ(22, e2->end_time);
}

struct BuildLogRecompactTest : public BuildLogTest {
  virtual bool IsPathDead(StringPiece s) const { return s == "out2"; }
};

TEST_F(BuildLogRecompactTest, Recompact) {
  AssertParse(&state_,
"build out: cat in\n"
"build out2: cat in\n");

  BuildLog log1;
  string err;
  EXPECT_TRUE(log1.OpenForWrite(kTestFilename, *this, &err));
  ASSERT_EQ("", err);
  // Record the same edge several times, to trigger recompaction
  // the next time the log is opened.
  for (int i = 0; i < 200; ++i)
    log1.RecordCommand(state_.edges_[0], 15, 18 + i);
  log1.RecordCommand(state_.edges_[1], 21, 22);
  log1.Close();

  // Load...
  BuildLog log2;
  EXPECT_TRUE(log2.Load(kTestFilename, &err));
  ASSERT_EQ("", err);
  ASSERT_EQ(2u, log2.entries().size());
  ASSERT_TRUE(log2.LookupByOutput("out"));
  ASSERT_TRUE(log2.LookupByOutput("out2"));
  // ...and force a recompaction.
  EXPECT_TRUE(log2.OpenForWrite(kTestFilename, *this, &err));
  log2.Close();

  // "out2" is dead, it should've been removed.
  BuildLog log3;
  EXPECT_TRUE(log2.Load(kTestFilename, &err));
  ASSERT_EQ("", err);
  ASSERT_EQ(1u, log2.entries().size());
  ASSERT_TRUE(log2.LookupByOutput("out"));
  ASSERT_FALSE(log2.LookupByOutput("out2"));
}

}  // anonymous namespace
<commit_msg>Null terminate the out2 string passed as filter2 to log.Restat<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
//
// 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.

#include "build_log.h"

#include "util.h"
#include "test.h"

#include <sys/stat.h>
#ifdef _WIN32
#include <fcntl.h>
#include <share.h>
#else
#include <sys/types.h>
#include <unistd.h>
#endif
#include <cassert>

namespace {

const char kTestFilename[] = "BuildLogTest-tempfile";

struct BuildLogTest : public StateTestWithBuiltinRules, public BuildLogUser {
  virtual void SetUp() {
    // In case a crashing test left a stale file behind.
    unlink(kTestFilename);
  }
  virtual void TearDown() {
    unlink(kTestFilename);
  }
  virtual bool IsPathDead(StringPiece s) const { return false; }
};

TEST_F(BuildLogTest, WriteRead) {
  AssertParse(&state_,
"build out: cat mid\n"
"build mid: cat in\n");

  BuildLog log1;
  string err;
  EXPECT_TRUE(log1.OpenForWrite(kTestFilename, *this, &err));
  ASSERT_EQ("", err);
  log1.RecordCommand(state_.edges_[0], 15, 18);
  log1.RecordCommand(state_.edges_[1], 20, 25);
  log1.Close();

  BuildLog log2;
  EXPECT_TRUE(log2.Load(kTestFilename, &err));
  ASSERT_EQ("", err);

  ASSERT_EQ(2u, log1.entries().size());
  ASSERT_EQ(2u, log2.entries().size());
  BuildLog::LogEntry* e1 = log1.LookupByOutput("out");
  ASSERT_TRUE(e1);
  BuildLog::LogEntry* e2 = log2.LookupByOutput("out");
  ASSERT_TRUE(e2);
  ASSERT_TRUE(*e1 == *e2);
  ASSERT_EQ(15, e1->start_time);
  ASSERT_EQ("out", e1->output);
}

TEST_F(BuildLogTest, FirstWriteAddsSignature) {
  const char kExpectedVersion[] = "# ninja log vX\n";
  const size_t kVersionPos = strlen(kExpectedVersion) - 2;  // Points at 'X'.

  BuildLog log;
  string contents, err;

  EXPECT_TRUE(log.OpenForWrite(kTestFilename, *this, &err));
  ASSERT_EQ("", err);
  log.Close();

  ASSERT_EQ(0, ReadFile(kTestFilename, &contents, &err));
  ASSERT_EQ("", err);
  if (contents.size() >= kVersionPos)
    contents[kVersionPos] = 'X';
  EXPECT_EQ(kExpectedVersion, contents);

  // Opening the file anew shouldn't add a second version string.
  EXPECT_TRUE(log.OpenForWrite(kTestFilename, *this, &err));
  ASSERT_EQ("", err);
  log.Close();

  contents.clear();
  ASSERT_EQ(0, ReadFile(kTestFilename, &contents, &err));
  ASSERT_EQ("", err);
  if (contents.size() >= kVersionPos)
    contents[kVersionPos] = 'X';
  EXPECT_EQ(kExpectedVersion, contents);
}

TEST_F(BuildLogTest, DoubleEntry) {
  FILE* f = fopen(kTestFilename, "wb");
  fprintf(f, "# ninja log v4\n");
  fprintf(f, "0\t1\t2\tout\tcommand abc\n");
  fprintf(f, "3\t4\t5\tout\tcommand def\n");
  fclose(f);

  string err;
  BuildLog log;
  EXPECT_TRUE(log.Load(kTestFilename, &err));
  ASSERT_EQ("", err);

  BuildLog::LogEntry* e = log.LookupByOutput("out");
  ASSERT_TRUE(e);
  ASSERT_NO_FATAL_FAILURE(AssertHash("command def", e->command_hash));
}

TEST_F(BuildLogTest, Truncate) {
  AssertParse(&state_,
"build out: cat mid\n"
"build mid: cat in\n");

  {
    BuildLog log1;
    string err;
    EXPECT_TRUE(log1.OpenForWrite(kTestFilename, *this, &err));
    ASSERT_EQ("", err);
    log1.RecordCommand(state_.edges_[0], 15, 18);
    log1.RecordCommand(state_.edges_[1], 20, 25);
    log1.Close();
  }

  struct stat statbuf;
  ASSERT_EQ(0, stat(kTestFilename, &statbuf));
  ASSERT_GT(statbuf.st_size, 0);

  // For all possible truncations of the input file, assert that we don't
  // crash when parsing.
  for (off_t size = statbuf.st_size; size > 0; --size) {
    BuildLog log2;
    string err;
    EXPECT_TRUE(log2.OpenForWrite(kTestFilename, *this, &err));
    ASSERT_EQ("", err);
    log2.RecordCommand(state_.edges_[0], 15, 18);
    log2.RecordCommand(state_.edges_[1], 20, 25);
    log2.Close();

    ASSERT_TRUE(Truncate(kTestFilename, size, &err));

    BuildLog log3;
    err.clear();
    ASSERT_TRUE(log3.Load(kTestFilename, &err) == LOAD_SUCCESS || !err.empty());
  }
}

TEST_F(BuildLogTest, ObsoleteOldVersion) {
  FILE* f = fopen(kTestFilename, "wb");
  fprintf(f, "# ninja log v3\n");
  fprintf(f, "123 456 0 out command\n");
  fclose(f);

  string err;
  BuildLog log;
  EXPECT_TRUE(log.Load(kTestFilename, &err));
  ASSERT_NE(err.find("version"), string::npos);
}

TEST_F(BuildLogTest, SpacesInOutputV4) {
  FILE* f = fopen(kTestFilename, "wb");
  fprintf(f, "# ninja log v4\n");
  fprintf(f, "123\t456\t456\tout with space\tcommand\n");
  fclose(f);

  string err;
  BuildLog log;
  EXPECT_TRUE(log.Load(kTestFilename, &err));
  ASSERT_EQ("", err);

  BuildLog::LogEntry* e = log.LookupByOutput("out with space");
  ASSERT_TRUE(e);
  ASSERT_EQ(123, e->start_time);
  ASSERT_EQ(456, e->end_time);
  ASSERT_EQ(456, e->mtime);
  ASSERT_NO_FATAL_FAILURE(AssertHash("command", e->command_hash));
}

TEST_F(BuildLogTest, DuplicateVersionHeader) {
  // Old versions of ninja accidentally wrote multiple version headers to the
  // build log on Windows. This shouldn't crash, and the second version header
  // should be ignored.
  FILE* f = fopen(kTestFilename, "wb");
  fprintf(f, "# ninja log v4\n");
  fprintf(f, "123\t456\t456\tout\tcommand\n");
  fprintf(f, "# ninja log v4\n");
  fprintf(f, "456\t789\t789\tout2\tcommand2\n");
  fclose(f);

  string err;
  BuildLog log;
  EXPECT_TRUE(log.Load(kTestFilename, &err));
  ASSERT_EQ("", err);

  BuildLog::LogEntry* e = log.LookupByOutput("out");
  ASSERT_TRUE(e);
  ASSERT_EQ(123, e->start_time);
  ASSERT_EQ(456, e->end_time);
  ASSERT_EQ(456, e->mtime);
  ASSERT_NO_FATAL_FAILURE(AssertHash("command", e->command_hash));

  e = log.LookupByOutput("out2");
  ASSERT_TRUE(e);
  ASSERT_EQ(456, e->start_time);
  ASSERT_EQ(789, e->end_time);
  ASSERT_EQ(789, e->mtime);
  ASSERT_NO_FATAL_FAILURE(AssertHash("command2", e->command_hash));
}

struct TestDiskInterface : public DiskInterface {
  virtual TimeStamp Stat(const string& path, string* err) const {
    return 4;
  }
  virtual bool WriteFile(const string& path, const string& contents) {
    assert(false);
    return true;
  }
  virtual bool MakeDir(const string& path) {
    assert(false);
    return false;
  }
  virtual Status ReadFile(const string& path, string* contents, string* err) {
    assert(false);
    return NotFound;
  }
  virtual int RemoveFile(const string& path) {
    assert(false);
    return 0;
  }
};

TEST_F(BuildLogTest, Restat) {
  FILE* f = fopen(kTestFilename, "wb");
  fprintf(f, "# ninja log v4\n"
             "1\t2\t3\tout\tcommand\n");
  fclose(f);
  std::string err;
  BuildLog log;
  EXPECT_TRUE(log.Load(kTestFilename, &err));
  ASSERT_EQ("", err);
  BuildLog::LogEntry* e = log.LookupByOutput("out");
  ASSERT_EQ(3, e->mtime);

  TestDiskInterface testDiskInterface;
  char out2[] = { 'o', 'u', 't', '2', 0 };
  char* filter2[] = { out2 };
  EXPECT_TRUE(log.Restat(kTestFilename, testDiskInterface, 1, filter2, &err));
  ASSERT_EQ("", err);
  e = log.LookupByOutput("out");
  ASSERT_EQ(3, e->mtime); // unchanged, since the filter doesn't match

  EXPECT_TRUE(log.Restat(kTestFilename, testDiskInterface, 0, NULL, &err));
  ASSERT_EQ("", err);
  e = log.LookupByOutput("out");
  ASSERT_EQ(4, e->mtime);
}

TEST_F(BuildLogTest, VeryLongInputLine) {
  // Ninja's build log buffer is currently 256kB. Lines longer than that are
  // silently ignored, but don't affect parsing of other lines.
  FILE* f = fopen(kTestFilename, "wb");
  fprintf(f, "# ninja log v4\n");
  fprintf(f, "123\t456\t456\tout\tcommand start");
  for (size_t i = 0; i < (512 << 10) / strlen(" more_command"); ++i)
    fputs(" more_command", f);
  fprintf(f, "\n");
  fprintf(f, "456\t789\t789\tout2\tcommand2\n");
  fclose(f);

  string err;
  BuildLog log;
  EXPECT_TRUE(log.Load(kTestFilename, &err));
  ASSERT_EQ("", err);

  BuildLog::LogEntry* e = log.LookupByOutput("out");
  ASSERT_EQ(NULL, e);

  e = log.LookupByOutput("out2");
  ASSERT_TRUE(e);
  ASSERT_EQ(456, e->start_time);
  ASSERT_EQ(789, e->end_time);
  ASSERT_EQ(789, e->mtime);
  ASSERT_NO_FATAL_FAILURE(AssertHash("command2", e->command_hash));
}

TEST_F(BuildLogTest, MultiTargetEdge) {
  AssertParse(&state_,
"build out out.d: cat\n");

  BuildLog log;
  log.RecordCommand(state_.edges_[0], 21, 22);

  ASSERT_EQ(2u, log.entries().size());
  BuildLog::LogEntry* e1 = log.LookupByOutput("out");
  ASSERT_TRUE(e1);
  BuildLog::LogEntry* e2 = log.LookupByOutput("out.d");
  ASSERT_TRUE(e2);
  ASSERT_EQ("out", e1->output);
  ASSERT_EQ("out.d", e2->output);
  ASSERT_EQ(21, e1->start_time);
  ASSERT_EQ(21, e2->start_time);
  ASSERT_EQ(22, e2->end_time);
  ASSERT_EQ(22, e2->end_time);
}

struct BuildLogRecompactTest : public BuildLogTest {
  virtual bool IsPathDead(StringPiece s) const { return s == "out2"; }
};

TEST_F(BuildLogRecompactTest, Recompact) {
  AssertParse(&state_,
"build out: cat in\n"
"build out2: cat in\n");

  BuildLog log1;
  string err;
  EXPECT_TRUE(log1.OpenForWrite(kTestFilename, *this, &err));
  ASSERT_EQ("", err);
  // Record the same edge several times, to trigger recompaction
  // the next time the log is opened.
  for (int i = 0; i < 200; ++i)
    log1.RecordCommand(state_.edges_[0], 15, 18 + i);
  log1.RecordCommand(state_.edges_[1], 21, 22);
  log1.Close();

  // Load...
  BuildLog log2;
  EXPECT_TRUE(log2.Load(kTestFilename, &err));
  ASSERT_EQ("", err);
  ASSERT_EQ(2u, log2.entries().size());
  ASSERT_TRUE(log2.LookupByOutput("out"));
  ASSERT_TRUE(log2.LookupByOutput("out2"));
  // ...and force a recompaction.
  EXPECT_TRUE(log2.OpenForWrite(kTestFilename, *this, &err));
  log2.Close();

  // "out2" is dead, it should've been removed.
  BuildLog log3;
  EXPECT_TRUE(log2.Load(kTestFilename, &err));
  ASSERT_EQ("", err);
  ASSERT_EQ(1u, log2.entries().size());
  ASSERT_TRUE(log2.LookupByOutput("out"));
  ASSERT_FALSE(log2.LookupByOutput("out2"));
}

}  // anonymous namespace
<|endoftext|>


<commit_before>// Python module for playing audio
// part of MusicPlayer, https://github.com/albertz/music-player
// Copyright (c) 2012, Albert Zeyer, www.az2000.de
// All rights reserved.
// This code is under the 2-clause BSD license, see License.txt in the root directory of this project.

// compile:
// gcc -c musicplayer*.cpp -I /System/Library/Frameworks/Python.framework/Headers/
// libtool -dynamic -o musicplayer.so musicplayer*.o -framework Python -lavformat -lavutil -lavcodec -lswresample -lportaudio -lc

// loosely based on ffplay.c
// https://github.com/FFmpeg/ffmpeg/blob/master/ffplay.c

// Similar to PyFFmpeg. http://code.google.com/p/pyffmpeg/
// This module is intended to be much simpler/high-level, though.

// Pyton interface:
//	createPlayer() -> player object with:
//		queue: song generator
//		peekQueue(n): list of upcoming songs. this should not change the queue. this also might not be accurate but that doesn't matter. it might also return less. it is used for caching and gapless playback. if the queue returns other songs later, it will just ignore these peeked songs. otherwise, it will use these caches.
//		playing: True or False, initially False
//		volume: 1.0 is norm; this is just a factor to each sample. default is 0.9
//		volumeSmoothClip: smooth clipping, see below. set to (1,1) to disable. default is (0.95,10)
//		curSong: current song (read only)
//		curSongPos: current song pos (read only)
//		curSongLen: current song len (read only)
//		curSongGainFactor: current song gain. read from song.gain (see below). can also be written
//		seekAbs(t) / seekRel(t): seeking functions (t in seconds, accepts float)
//		nextSong(): skip to next song function
//	song object expected interface:
//		readPacket(bufSize): should return some string
//		seekRaw(offset, whence): should seek and return the current pos
//		gain: some gain in decible, e.g. calculated by calcReplayGain. if not present, is ignored
//		url: some url, can be anything printable (not used at the moment)
//	and other functions, see their embedded doc ...

#include "musicplayer.h"

static PyMethodDef module_methods[] = {
	{"createPlayer",	(PyCFunction)pyCreatePlayer,	METH_NOARGS,	"creates new player"},
	{"getSoundDevices", (PyCFunction)pyGetSoundDevices, METH_NOARGS,	"get list of sound device names"},
	{"getMetadata",		pyGetMetadata,	METH_VARARGS,	"get metadata for Song"},
	{"calcAcoustIdFingerprint",		pyCalcAcoustIdFingerprint,	METH_VARARGS,	"calculate AcoustID fingerprint for Song"},
	{"calcBitmapThumbnail",		(PyCFunction)pyCalcBitmapThumbnail,	METH_VARARGS|METH_KEYWORDS,	"calculate bitmap thumbnail for Song"},
	{"calcReplayGain",		(PyCFunction)pyCalcReplayGain,	METH_VARARGS|METH_KEYWORDS,	"calculate ReplayGain for Song"},
	{"setFfmpegLogLevel",		pySetFfmpegLogLevel,	METH_VARARGS,	"set FFmpeg log level (av_log_set_level)"},
	{"enableDebugLog",	(PyCFunction)pyEnableDebugLog,	METH_VARARGS,	"enable/disable debug log"},
	{NULL,				NULL}	/* sentinel */
};

PyDoc_STRVAR(module_doc,
"Music player.");

static PyObject* EventClass = NULL;

static void init() {
	PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
	initPlayerOutput();
	initPlayerDecoder();
}

PyMODINIT_FUNC
initmusicplayer(void)
{
	//printf("initmusicplayer\n");
	init();
	if (PyType_Ready(&Player_Type) < 0)
		Py_FatalError("Can't initialize player type");
	PyObject* m = Py_InitModule3("musicplayer", module_methods, module_doc);
	if(!m) {
		Py_FatalError("Can't initialize musicplayer module");
		return;
	}

	if(EventClass == NULL) {
		PyObject* classDict = PyDict_New();
		assert(classDict);
		PyObject* className = PyString_FromString("Event");
		assert(className);
		EventClass = PyClass_New(NULL, classDict, className);
		assert(EventClass);
		Py_XDECREF(classDict); classDict = NULL;
		Py_XDECREF(className); className = NULL;
	}

	if(EventClass) {
		Py_INCREF(EventClass);
		PyModule_AddObject(m, "Event", EventClass); // takes the ref
	}
}
<commit_msg>Python 3<commit_after>// Python module for playing audio
// part of MusicPlayer, https://github.com/albertz/music-player
// Copyright (c) 2012, Albert Zeyer, www.az2000.de
// All rights reserved.
// This code is under the 2-clause BSD license, see License.txt in the root directory of this project.

// compile:
// gcc -c musicplayer*.cpp -I /System/Library/Frameworks/Python.framework/Headers/
// libtool -dynamic -o musicplayer.so musicplayer*.o -framework Python -lavformat -lavutil -lavcodec -lswresample -lportaudio -lc

// loosely based on ffplay.c
// https://github.com/FFmpeg/ffmpeg/blob/master/ffplay.c

// Similar to PyFFmpeg. http://code.google.com/p/pyffmpeg/
// This module is intended to be much simpler/high-level, though.

// Pyton interface:
//	createPlayer() -> player object with:
//		queue: song generator
//		peekQueue(n): list of upcoming songs. this should not change the queue. this also might not be accurate but that doesn't matter. it might also return less. it is used for caching and gapless playback. if the queue returns other songs later, it will just ignore these peeked songs. otherwise, it will use these caches.
//		playing: True or False, initially False
//		volume: 1.0 is norm; this is just a factor to each sample. default is 0.9
//		volumeSmoothClip: smooth clipping, see below. set to (1,1) to disable. default is (0.95,10)
//		curSong: current song (read only)
//		curSongPos: current song pos (read only)
//		curSongLen: current song len (read only)
//		curSongGainFactor: current song gain. read from song.gain (see below). can also be written
//		seekAbs(t) / seekRel(t): seeking functions (t in seconds, accepts float)
//		nextSong(): skip to next song function
//	song object expected interface:
//		readPacket(bufSize): should return some string
//		seekRaw(offset, whence): should seek and return the current pos
//		gain: some gain in decible, e.g. calculated by calcReplayGain. if not present, is ignored
//		url: some url, can be anything printable (not used at the moment)
//	and other functions, see their embedded doc ...

#include "musicplayer.h"

#define module_name "musicplayer"

static PyMethodDef module_methods[] = {
	{"createPlayer",	(PyCFunction)pyCreatePlayer,	METH_NOARGS,	"creates new player"},
	{"getSoundDevices", (PyCFunction)pyGetSoundDevices, METH_NOARGS,	"get list of sound device names"},
	{"getMetadata",		pyGetMetadata,	METH_VARARGS,	"get metadata for Song"},
	{"calcAcoustIdFingerprint",		pyCalcAcoustIdFingerprint,	METH_VARARGS,	"calculate AcoustID fingerprint for Song"},
	{"calcBitmapThumbnail",		(PyCFunction)pyCalcBitmapThumbnail,	METH_VARARGS|METH_KEYWORDS,	"calculate bitmap thumbnail for Song"},
	{"calcReplayGain",		(PyCFunction)pyCalcReplayGain,	METH_VARARGS|METH_KEYWORDS,	"calculate ReplayGain for Song"},
	{"setFfmpegLogLevel",		pySetFfmpegLogLevel,	METH_VARARGS,	"set FFmpeg log level (av_log_set_level)"},
	{"enableDebugLog",	(PyCFunction)pyEnableDebugLog,	METH_VARARGS,	"enable/disable debug log"},
	{NULL,				NULL}	/* sentinel */
};

PyDoc_STRVAR(module_doc, "Music player.");

#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef module_def = {
	PyModuleDef_HEAD_INIT,
	module_name,     /* m_name */
	module_doc,  /* m_doc */
	-1,                  /* m_size */
	module_methods,    /* m_methods */
	NULL,                /* m_reload */
	NULL,                /* m_traverse */
	NULL,                /* m_clear */
	NULL,                /* m_free */
};
#endif

static PyObject* EventClass = NULL;

static void init() {
	PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
	initPlayerOutput();
	initPlayerDecoder();
}

#if PY_MAJOR_VERSION == 2
PyMODINIT_FUNC initmusicplayer(void)
#else
PyMODINIT_FUNC PyInit_musicplayer(void)
#endif
{
	//printf("initmusicplayer\n");
	init();
	if (PyType_Ready(&Player_Type) < 0)
		Py_FatalError("Can't initialize player type");

#if PY_MAJOR_VERSION == 2
	PyObject* m = Py_InitModule3(module_name, module_methods, module_doc);
#else
	PyObject* m = PyModule_Create(&module_def);
#endif
	if(!m) {
		Py_FatalError("Can't initialize " module_name " module");
		goto error;
	}

	if(EventClass == NULL) {
		PyObject* classDict = PyDict_New();
		assert(classDict);
#if PY_MAJOR_VERSION == 2
		PyObject* className = PyString_FromString("Event");
#else
		PyObject* className = PyUnicode_FromString("Event");
#endif
		assert(className);
#if PY_MAJOR_VERSION == 2
		EventClass = PyClass_New(NULL, classDict, className);
#else
		PyObject* classBases = PyTuple_New(0);
		EventClass = PyObject_CallFunctionObjArgs((PyObject *)&PyType_Type, className, classBases, classDict, NULL);
		Py_XDECREF(classBases);
#endif
		assert(EventClass);
		Py_XDECREF(classDict); classDict = NULL;
		Py_XDECREF(className); className = NULL;
	}

	if(EventClass) {
		Py_INCREF(EventClass);
		PyModule_AddObject(m, "Event", EventClass); // takes the ref
	}

#if PY_MAJOR_VERSION == 2
error:
	return;
#else
	return m;
error:
	return NULL;
#endif
}
<|endoftext|>


<commit_before>#include <sys/mount.h>
#include <v8.h>
#include <node.h>

v8::Handle<v8::Value> Mount(const v8::Arguments &args) {
  v8::HandleScope scope;

  if (args.Length() < 3) {
    // TODO: make it raise a proper exception
    return v8::ThrowException(v8::String::New("`mount` needs at least 3 parameters"));
  }

  bool callback = false;
  v8::Local<v8::Function> cb;

  if(args.Length() == 4) {
    callback = true;
    cb = v8::Local<v8::Function>::Cast(args[3]);
  }

  v8::String::Utf8Value device(args[0]->ToString());
  v8::String::Utf8Value path(args[1]->ToString());
  v8::String::Utf8Value type(args[2]->ToString());

  bool mountAction = (mount(*device, *path, *type, 0, NULL) == 0) ? true : false;
  // TODO: expose flag values
  v8::Local<v8::Value> mounted = v8::Local<v8::Value>::New(v8::Boolean::New(mountAction));

  if(callback) {
    const unsigned argc = 1;
    v8::Local<v8::Value> argv[argc] = {mounted};
    cb->Call(v8::Context::GetCurrent()->Global(), argc, argv);
  }
  return mounted;
}

v8::Handle<v8::Value> Umount(const v8::Arguments &args) {
  v8::HandleScope scope;

  if (args.Length() < 1) {
    return v8::ThrowException(v8::String::New("`umount` needs at least 1 parameter"));
  }

  bool callback = false;
  v8::Local<v8::Function> cb;

  if(args.Length() == 2) {
    callback = true;
    cb = v8::Local<v8::Function>::Cast(args[1]);
  }

  v8::String::Utf8Value path(args[0]->ToString());

  bool mountAction = (umount(*path) == 0) ? true : false;

  v8::Local<v8::Value> mounted = v8::Local<v8::Value>::New(v8::Boolean::New(mountAction));

  if(callback) {
    const unsigned argc = 1;
    v8::Local<v8::Value> argv[argc] = {mounted};
    cb->Call(v8::Context::GetCurrent()->Global(), argc, argv);
  }
  return mounted;
}

void init (v8::Handle<v8::Object> exports, v8::Handle<v8::Object> module) {
  exports->Set(v8::String::NewSymbol("mount"), v8::FunctionTemplate::New(Mount)->GetFunction());
  exports->Set(v8::String::NewSymbol("umount"), v8::FunctionTemplate::New(Umount)->GetFunction());
}
NODE_MODULE(mount, init)

<commit_msg>Added mount options support<commit_after>#include <sys/mount.h>
#include <v8.h>
#include <node.h>

v8::Handle<v8::Value> Mount(const v8::Arguments &args) {
  v8::HandleScope scope;

  if (args.Length() < 3) {
    // TODO: make it raise a proper exception
    return v8::ThrowException(v8::String::New("`mount` needs at least 3 parameters"));
  }

  bool callback = false;
  v8::Local<v8::Function> cb;
  v8::Local<v8::Array> options;

  if(args.Length() == 4) {
    callback = true;
    cb = v8::Local<v8::Function>::Cast(args[3]);
  } else if(args.Length() == 5) {
    callback = true;
    cb = v8::Local<v8::Function>::Cast(args[4]);
    if (args[3]->IsArray()) {
      v8::Handle<v8::Array> options = v8::Handle<v8::Array>::Cast(args[3]);
    }
  }

  int mask = 0;
  if(options->Length() > 0) {
    for (int i = 0; i < options->Length(); i++) {
      v8::Local<v8::String> opt = v8::Local<v8::String>::Cast(options->Get(i));
      if(opt == v8::String::New("bind")) {
        mask = mask | MS_BIND;
      } else if(opt == v8::String::New("readonly")) {
        mask = mask | MS_RDONLY;
      } else if(opt == v8::String::New("remount")) {
        mask = mask | MS_REMOUNT;
      }
    }
  }

  v8::String::Utf8Value device(args[0]->ToString());
  v8::String::Utf8Value path(args[1]->ToString());
  v8::String::Utf8Value type(args[2]->ToString());

  bool mountAction = (mount(*device, *path, *type, mask, NULL) == 0) ? true : false;

  v8::Local<v8::Value> mounted = v8::Local<v8::Value>::New(v8::Boolean::New(mountAction));

  if(callback) {
    const unsigned argc = 1;
    v8::Local<v8::Value> argv[argc] = {mounted};
    cb->Call(v8::Context::GetCurrent()->Global(), argc, argv);
  }
  return mounted;
}

v8::Handle<v8::Value> Umount(const v8::Arguments &args) {
  v8::HandleScope scope;

  if (args.Length() < 1) {
    return v8::ThrowException(v8::String::New("`umount` needs at least 1 parameter"));
  }

  bool callback = false;
  v8::Local<v8::Function> cb;

  if(args.Length() == 2) {
    callback = true;
    cb = v8::Local<v8::Function>::Cast(args[1]);
  }

  v8::String::Utf8Value path(args[0]->ToString());

  bool mountAction = (umount(*path) == 0) ? true : false;

  v8::Local<v8::Value> mounted = v8::Local<v8::Value>::New(v8::Boolean::New(mountAction));

  if(callback) {
    const unsigned argc = 1;
    v8::Local<v8::Value> argv[argc] = {mounted};
    cb->Call(v8::Context::GetCurrent()->Global(), argc, argv);
  }
  return mounted;
}

void init (v8::Handle<v8::Object> exports, v8::Handle<v8::Object> module) {
  exports->Set(v8::String::NewSymbol("mount"), v8::FunctionTemplate::New(Mount)->GetFunction());
  exports->Set(v8::String::NewSymbol("umount"), v8::FunctionTemplate::New(Umount)->GetFunction());
}
NODE_MODULE(mount, init)

<|endoftext|>