<commit_before>// Copyright (c) 2014, Salesforce.com, Inc.  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// - Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
// - Neither the name of Salesforce.com nor the names of its contributors
//   may be used to endorse or promote products derived from this
//   software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#pragma once

#include <utility>
#include <vector>
#include <random>
#include <distributions/common.hpp>
#include <distributions/special.hpp>
#include <distributions/vector_math.hpp>
#include <distributions/random_fwd.hpp>

#include <eigen3/Eigen/Cholesky>

namespace distributions {

inline int sample_int(rng_t & rng, int low, int high) {
    std::uniform_int_distribution<> sampler(low, high);
    return sampler(rng);
}

inline float sample_unif01(rng_t & rng) {
    std::uniform_real_distribution<float> sampler(0.0, 1.0);
    return sampler(rng);
}

inline bool sample_bernoulli(rng_t & rng, float p) {
    std::uniform_real_distribution<float> sampler(0.0, 1.0);
    return sampler(rng) < p;
}

inline float sample_std_normal(rng_t & rng) {
    std::normal_distribution<float> sampler(0.f, 1.f);
    return sampler(rng);
}

inline float sample_normal(rng_t & rng, float mean, float variance) {
    float stddev = sqrtf(variance);
    std::normal_distribution<float> sampler(mean, stddev);
    return sampler(rng);
}

inline float sample_chisq(rng_t & rng, float nu) {
    // HACK <float> appears to be broken in libstdc++ 4.6
    // typedef std::chi_squared_distribution<float> chi_squared_distribution_t;
    typedef std::chi_squared_distribution<double> chi_squared_distribution_t;

    chi_squared_distribution_t sampler(nu);
    return sampler(rng);
}

inline int sample_poisson(rng_t & rng, float mean) {
    std::poisson_distribution<int> sampler(mean);
    return sampler(rng);
}

inline int sample_negative_binomial(rng_t & rng, float p, int r) {
    std::negative_binomial_distribution<int> sampler(r, p);
    return sampler(rng);
}

inline float sample_gamma(
        rng_t & rng,
        float alpha,
        float beta = 1.f) {
    // HACK <float> appears to be broken in libstdc++ 4.6
    // typedef std::gamma_distribution<float> gamma_distribution_t;
    typedef std::gamma_distribution<double> gamma_distribution_t;

    gamma_distribution_t sampler(alpha, beta);
    return sampler(rng);
}

inline float sample_beta(
        rng_t & rng,
        float alpha,
        float beta) {
    float x = sample_gamma(rng, alpha);
    float y = sample_gamma(rng, beta);
    if (x==0 && y==0) return sample_bernoulli(rng, alpha / (alpha + beta)) ? 1.0 : 0.0;
    return x / (x + y);
}

inline float sample_beta_safe(
        rng_t & rng,
        float alpha,
        float beta,
        float min_value) {
    DIST_ASSERT(min_value >= 0, "bad bound: " << min_value);
    DIST_ASSERT(alpha > 0, "bad alpha = " << alpha);
    float p = sample_beta(rng, alpha, beta);
    return (p + min_value) / (1.f + min_value);
}

void sample_dirichlet(
        rng_t & rng,
        size_t dim,
        const float * alphas,
        float * probs);

void sample_dirichlet_safe(
        rng_t & rng,
        size_t dim,
        const float * alphas,
        float * probs,
        float min_value);

inline float fast_score_student_t(
        float x,
        float nu,
        float mu,
        float lambda) {
    // \cite{murphy2007conjugate}, Eq. 304
    float p = 0.f;
    p += fast_lgamma_nu(nu);
    p += 0.5f * fast_log(lambda / (M_PIf * nu));
    p += (-0.5f * nu - 0.5f) * fast_log(1.f + (lambda * sqr(x - mu)) / nu);
    return p;
}

inline float score_student_t(
        float x,
        float nu,
        float mu,
        float lambda) {
    // \cite{murphy2007conjugate}, Eq. 304
    float p = lgammaf(nu * 0.5f + 0.5f) - lgammaf(nu * 0.5f);
    p += 0.5f * logf(lambda / (M_PIf * nu));
    p += (-0.5f * nu - 0.5f) * logf(1.f + (lambda * sqr(x - mu)) / nu);
    return p;
}

// XXX: not optimized for speed
template <typename Vector, typename Matrix>
inline float score_mv_student_t(
        const Vector & v,
        float nu,
        const Vector & mu,
        const Matrix & sigma) {
  const unsigned d = v.size();
  const float term1 = fast_lgamma(nu / 2. + static_cast<float>(d) / 2.)
      - fast_lgamma(nu / 2.);

  // XXX: use Cholesky decomposition to make this faster
  const Matrix sigma_inv = sigma.inverse();
  const float sigma_det = sigma.determinant();

  const float log_pi = 1.1447298858494002;

  const float term2 = -0.5 * fast_log(sigma_det)
      - static_cast<float>(d) / 2. * (fast_log(nu) + log_pi);

  const Vector diff = v - mu;

  const float term3 = -0.5 * (nu + static_cast<float>(d)) *
      fast_log(1. + 1. / nu * (diff.dot(sigma_inv * diff)));

  return term1 + term2 + term3;
}

// Assumes sigma is positive definite
template <typename Vector, typename Matrix>
inline Vector sample_multivariate_normal(
        const Vector & mu,
        const Matrix & sigma,
        rng_t & rng) {
    DIST_ASSERT_EQ(sigma.rows(), sigma.cols());
    DIST_ASSERT_EQ(mu.size(), sigma.rows());

    Eigen::LLT<Matrix> llt(sigma);
    DIST_ASSERT_EQ(llt.info(), Eigen::Success);

    Vector z(mu.size());
    std::normal_distribution<float> norm;
    for (unsigned i = 0; i < mu.size(); i++) {
        z(i) = norm(rng);
    }

    return mu + llt.matrixL() * z;
}

// Based on:
// http://www.mit.edu/~mattjj/released-code/hsmm/stats_util.py
template <typename Matrix>
inline Matrix sample_wishart(
        float nu,
        const Matrix & scale,
        rng_t & rng) {
    DIST_ASSERT_EQ(scale.rows(), scale.cols());

    Eigen::LLT<Matrix> llt(scale);
    DIST_ASSERT_EQ(llt.info(), Eigen::Success);

    const unsigned size = scale.rows();
    Matrix A = Matrix::Zero(size, size);

    for (unsigned i = 0; i < size; i++) {
        A(i, i) = sqrt(sample_chisq(rng, nu - static_cast<float>(i)));
    }

    std::normal_distribution<float> norm;
    for (unsigned i = 1; i < size; i++) {
        for (unsigned j = 0; j < i; j++) {
            A(i, j) = norm(rng);
        }
    }

    const Matrix X = llt.matrixL() * A;
    return X * X.transpose();
}

// XXX: not optimized for speed
template <typename Matrix>
inline Matrix sample_inverse_wishart(
        float nu,
        const Matrix & psi,
        rng_t & rng) {
    const Matrix psi_inv = psi.inverse();
    const Matrix sigma_inv = sample_wishart(nu, psi_inv, rng);
    return sigma_inv.inverse();
}

template <typename Vector, typename Matrix>
inline std::pair<Vector, Matrix> sample_normal_inverse_wishart(
        const Vector & mu0,
        float lambda,
        const Matrix & psi,
        float nu,
        rng_t & rng) {
    Matrix cov = 1./lambda * sample_inverse_wishart(nu, psi, rng);
    Vector mu = sample_multivariate_normal(mu0, cov, rng);
    return std::make_pair(std::move(mu), std::move(cov));
}

template<class T>
inline T sample_from_urn(
        rng_t & rng,
        const std::vector<T> & urn) {
    DIST_ASSERT(urn.size() >= 1, "urn is too small to sample from");
    size_t f = sample_int(rng, 0, urn.size() - 1);
    DIST_ASSERT(0 <= f and f < urn.size(), "bad value: " << f);
    return urn[f];
}

template<class T>
inline std::pair<T, T> sample_pair_from_urn(
        rng_t & rng,
        const std::vector<T> & urn) {
    DIST_ASSERT(urn.size() >= 2, "urn is too small to sample pair from");
    size_t f1 = sample_int(rng, 0, urn.size() - 1);
    size_t f2 = sample_int(rng, 0, urn.size() - 2);
    if (f2 >= f1) {
        f2 += 1;
    }
    DIST_ASSERT(0 <= f1 and f1 < urn.size(), "bad value: " << f1);
    DIST_ASSERT(0 <= f2 and f2 < urn.size(), "bad value: " << f2);
    DIST_ASSERT(f1 != f2, "bad pair: " << f1 << ", " << f2);
    return std::make_pair(urn[f1], urn[f2]);
}

// --------------------------------------------------------------------------
// Discrete Distribution
//
// Terminology:
//
//         prob = probability
//   likelihood = non-normalized probability
//        score = non-normalized log probability

template<class Alloc>
float log_sum_exp(const std::vector<float, Alloc> & scores);

inline size_t sample_discrete(
        rng_t & rng,
        size_t dim,
        const float * probs) {
    DIST_ASSERT_LT(0, dim);
    float t = sample_unif01(rng);
    for (size_t i = 0; DIST_LIKELY(i < dim - 1); ++i) {
        t -= probs[i];
        if (DIST_UNLIKELY(t < 0)) {
            return i;
        }
    }
    return dim - 1;
}

template<class Alloc>
inline size_t sample_from_likelihoods(
        rng_t & rng,
        const std::vector<float, Alloc> & likelihoods,
        float total_likelihood) {
    const size_t size = likelihoods.size();
    DIST_ASSERT_LT(0, size);

    float t = total_likelihood * sample_unif01(rng);

    for (size_t i = 0; DIST_LIKELY(i < size); ++i) {
        t -= likelihoods[i];
        if (DIST_UNLIKELY(t <= 0)) {
            return i;
        }
    }

    return size - 1;
}

template<class Alloc>
inline size_t sample_from_likelihoods(
        rng_t & rng,
        const std::vector<float, Alloc> & likelihoods) {
    float total = vector_sum(likelihoods.size(), likelihoods.data());
    return sample_from_likelihoods(rng, likelihoods, total);
}

template<class Alloc>
inline size_t sample_from_probs(
        rng_t & rng,
        const std::vector<float, Alloc> & probs) {
    return sample_from_likelihoods(rng, probs, 1.f);
}

// returns total likelihood
template<class Alloc>
float scores_to_likelihoods(std::vector<float, Alloc> & scores);

template<class Alloc>
void scores_to_probs(std::vector<float, Alloc> & scores) {
    float total = scores_to_likelihoods(scores);
    vector_scale(scores.size(), scores.data(), 1.f / total);
}

template<class Alloc>
inline size_t sample_from_scores_overwrite(
        rng_t & rng,
        std::vector<float, Alloc> & scores) {
    float total = scores_to_likelihoods(scores);
    return sample_from_likelihoods(rng, scores, total);
}

template<class Alloc>
inline std::pair<size_t, float> sample_prob_from_scores_overwrite(
        rng_t & rng,
        std::vector<float, Alloc> & scores) {
    float total = scores_to_likelihoods(scores);
    size_t sample = sample_from_likelihoods(rng, scores, total);
    float prob = scores[sample] / total;
    return std::make_pair(sample, prob);
}

// score_from_scores_overwrite(...) = log(prob_from_scores_overwrite(...)),
// this is less succeptible to overflow than prob_from_scores_overwrite
template<class Alloc>
float score_from_scores_overwrite(
        rng_t & rng,
        size_t sample,
        std::vector<float, Alloc> & scores);

template<class Alloc>
inline size_t sample_from_scores(
        rng_t & rng,
        const std::vector<float, Alloc> & scores) {
    std::vector<float, Alloc> scores_copy(scores);
    return sample_from_scores_overwrite(rng, scores_copy);
}

}  // namespace distributions
<commit_msg>Added new line to get line under 80 characters<commit_after>// Copyright (c) 2014, Salesforce.com, Inc.  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// - Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
// - Neither the name of Salesforce.com nor the names of its contributors
//   may be used to endorse or promote products derived from this
//   software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#pragma once

#include <utility>
#include <vector>
#include <random>
#include <distributions/common.hpp>
#include <distributions/special.hpp>
#include <distributions/vector_math.hpp>
#include <distributions/random_fwd.hpp>

#include <eigen3/Eigen/Cholesky>

namespace distributions {

inline int sample_int(rng_t & rng, int low, int high) {
    std::uniform_int_distribution<> sampler(low, high);
    return sampler(rng);
}

inline float sample_unif01(rng_t & rng) {
    std::uniform_real_distribution<float> sampler(0.0, 1.0);
    return sampler(rng);
}

inline bool sample_bernoulli(rng_t & rng, float p) {
    std::uniform_real_distribution<float> sampler(0.0, 1.0);
    return sampler(rng) < p;
}

inline float sample_std_normal(rng_t & rng) {
    std::normal_distribution<float> sampler(0.f, 1.f);
    return sampler(rng);
}

inline float sample_normal(rng_t & rng, float mean, float variance) {
    float stddev = sqrtf(variance);
    std::normal_distribution<float> sampler(mean, stddev);
    return sampler(rng);
}

inline float sample_chisq(rng_t & rng, float nu) {
    // HACK <float> appears to be broken in libstdc++ 4.6
    // typedef std::chi_squared_distribution<float> chi_squared_distribution_t;
    typedef std::chi_squared_distribution<double> chi_squared_distribution_t;

    chi_squared_distribution_t sampler(nu);
    return sampler(rng);
}

inline int sample_poisson(rng_t & rng, float mean) {
    std::poisson_distribution<int> sampler(mean);
    return sampler(rng);
}

inline int sample_negative_binomial(rng_t & rng, float p, int r) {
    std::negative_binomial_distribution<int> sampler(r, p);
    return sampler(rng);
}

inline float sample_gamma(
        rng_t & rng,
        float alpha,
        float beta = 1.f) {
    // HACK <float> appears to be broken in libstdc++ 4.6
    // typedef std::gamma_distribution<float> gamma_distribution_t;
    typedef std::gamma_distribution<double> gamma_distribution_t;

    gamma_distribution_t sampler(alpha, beta);
    return sampler(rng);
}

inline float sample_beta(
        rng_t & rng,
        float alpha,
        float beta) {
    float x = sample_gamma(rng, alpha);
    float y = sample_gamma(rng, beta);
    if (x==0 && y==0)
        return sample_bernoulli(rng, alpha / (alpha + beta)) ? 1.0 : 0.0;
    return x / (x + y);
}

inline float sample_beta_safe(
        rng_t & rng,
        float alpha,
        float beta,
        float min_value) {
    DIST_ASSERT(min_value >= 0, "bad bound: " << min_value);
    DIST_ASSERT(alpha > 0, "bad alpha = " << alpha);
    float p = sample_beta(rng, alpha, beta);
    return (p + min_value) / (1.f + min_value);
}

void sample_dirichlet(
        rng_t & rng,
        size_t dim,
        const float * alphas,
        float * probs);

void sample_dirichlet_safe(
        rng_t & rng,
        size_t dim,
        const float * alphas,
        float * probs,
        float min_value);

inline float fast_score_student_t(
        float x,
        float nu,
        float mu,
        float lambda) {
    // \cite{murphy2007conjugate}, Eq. 304
    float p = 0.f;
    p += fast_lgamma_nu(nu);
    p += 0.5f * fast_log(lambda / (M_PIf * nu));
    p += (-0.5f * nu - 0.5f) * fast_log(1.f + (lambda * sqr(x - mu)) / nu);
    return p;
}

inline float score_student_t(
        float x,
        float nu,
        float mu,
        float lambda) {
    // \cite{murphy2007conjugate}, Eq. 304
    float p = lgammaf(nu * 0.5f + 0.5f) - lgammaf(nu * 0.5f);
    p += 0.5f * logf(lambda / (M_PIf * nu));
    p += (-0.5f * nu - 0.5f) * logf(1.f + (lambda * sqr(x - mu)) / nu);
    return p;
}

// XXX: not optimized for speed
template <typename Vector, typename Matrix>
inline float score_mv_student_t(
        const Vector & v,
        float nu,
        const Vector & mu,
        const Matrix & sigma) {
  const unsigned d = v.size();
  const float term1 = fast_lgamma(nu / 2. + static_cast<float>(d) / 2.)
      - fast_lgamma(nu / 2.);

  // XXX: use Cholesky decomposition to make this faster
  const Matrix sigma_inv = sigma.inverse();
  const float sigma_det = sigma.determinant();

  const float log_pi = 1.1447298858494002;

  const float term2 = -0.5 * fast_log(sigma_det)
      - static_cast<float>(d) / 2. * (fast_log(nu) + log_pi);

  const Vector diff = v - mu;

  const float term3 = -0.5 * (nu + static_cast<float>(d)) *
      fast_log(1. + 1. / nu * (diff.dot(sigma_inv * diff)));

  return term1 + term2 + term3;
}

// Assumes sigma is positive definite
template <typename Vector, typename Matrix>
inline Vector sample_multivariate_normal(
        const Vector & mu,
        const Matrix & sigma,
        rng_t & rng) {
    DIST_ASSERT_EQ(sigma.rows(), sigma.cols());
    DIST_ASSERT_EQ(mu.size(), sigma.rows());

    Eigen::LLT<Matrix> llt(sigma);
    DIST_ASSERT_EQ(llt.info(), Eigen::Success);

    Vector z(mu.size());
    std::normal_distribution<float> norm;
    for (unsigned i = 0; i < mu.size(); i++) {
        z(i) = norm(rng);
    }

    return mu + llt.matrixL() * z;
}

// Based on:
// http://www.mit.edu/~mattjj/released-code/hsmm/stats_util.py
template <typename Matrix>
inline Matrix sample_wishart(
        float nu,
        const Matrix & scale,
        rng_t & rng) {
    DIST_ASSERT_EQ(scale.rows(), scale.cols());

    Eigen::LLT<Matrix> llt(scale);
    DIST_ASSERT_EQ(llt.info(), Eigen::Success);

    const unsigned size = scale.rows();
    Matrix A = Matrix::Zero(size, size);

    for (unsigned i = 0; i < size; i++) {
        A(i, i) = sqrt(sample_chisq(rng, nu - static_cast<float>(i)));
    }

    std::normal_distribution<float> norm;
    for (unsigned i = 1; i < size; i++) {
        for (unsigned j = 0; j < i; j++) {
            A(i, j) = norm(rng);
        }
    }

    const Matrix X = llt.matrixL() * A;
    return X * X.transpose();
}

// XXX: not optimized for speed
template <typename Matrix>
inline Matrix sample_inverse_wishart(
        float nu,
        const Matrix & psi,
        rng_t & rng) {
    const Matrix psi_inv = psi.inverse();
    const Matrix sigma_inv = sample_wishart(nu, psi_inv, rng);
    return sigma_inv.inverse();
}

template <typename Vector, typename Matrix>
inline std::pair<Vector, Matrix> sample_normal_inverse_wishart(
        const Vector & mu0,
        float lambda,
        const Matrix & psi,
        float nu,
        rng_t & rng) {
    Matrix cov = 1./lambda * sample_inverse_wishart(nu, psi, rng);
    Vector mu = sample_multivariate_normal(mu0, cov, rng);
    return std::make_pair(std::move(mu), std::move(cov));
}

template<class T>
inline T sample_from_urn(
        rng_t & rng,
        const std::vector<T> & urn) {
    DIST_ASSERT(urn.size() >= 1, "urn is too small to sample from");
    size_t f = sample_int(rng, 0, urn.size() - 1);
    DIST_ASSERT(0 <= f and f < urn.size(), "bad value: " << f);
    return urn[f];
}

template<class T>
inline std::pair<T, T> sample_pair_from_urn(
        rng_t & rng,
        const std::vector<T> & urn) {
    DIST_ASSERT(urn.size() >= 2, "urn is too small to sample pair from");
    size_t f1 = sample_int(rng, 0, urn.size() - 1);
    size_t f2 = sample_int(rng, 0, urn.size() - 2);
    if (f2 >= f1) {
        f2 += 1;
    }
    DIST_ASSERT(0 <= f1 and f1 < urn.size(), "bad value: " << f1);
    DIST_ASSERT(0 <= f2 and f2 < urn.size(), "bad value: " << f2);
    DIST_ASSERT(f1 != f2, "bad pair: " << f1 << ", " << f2);
    return std::make_pair(urn[f1], urn[f2]);
}

// --------------------------------------------------------------------------
// Discrete Distribution
//
// Terminology:
//
//         prob = probability
//   likelihood = non-normalized probability
//        score = non-normalized log probability

template<class Alloc>
float log_sum_exp(const std::vector<float, Alloc> & scores);

inline size_t sample_discrete(
        rng_t & rng,
        size_t dim,
        const float * probs) {
    DIST_ASSERT_LT(0, dim);
    float t = sample_unif01(rng);
    for (size_t i = 0; DIST_LIKELY(i < dim - 1); ++i) {
        t -= probs[i];
        if (DIST_UNLIKELY(t < 0)) {
            return i;
        }
    }
    return dim - 1;
}

template<class Alloc>
inline size_t sample_from_likelihoods(
        rng_t & rng,
        const std::vector<float, Alloc> & likelihoods,
        float total_likelihood) {
    const size_t size = likelihoods.size();
    DIST_ASSERT_LT(0, size);

    float t = total_likelihood * sample_unif01(rng);

    for (size_t i = 0; DIST_LIKELY(i < size); ++i) {
        t -= likelihoods[i];
        if (DIST_UNLIKELY(t <= 0)) {
            return i;
        }
    }

    return size - 1;
}

template<class Alloc>
inline size_t sample_from_likelihoods(
        rng_t & rng,
        const std::vector<float, Alloc> & likelihoods) {
    float total = vector_sum(likelihoods.size(), likelihoods.data());
    return sample_from_likelihoods(rng, likelihoods, total);
}

template<class Alloc>
inline size_t sample_from_probs(
        rng_t & rng,
        const std::vector<float, Alloc> & probs) {
    return sample_from_likelihoods(rng, probs, 1.f);
}

// returns total likelihood
template<class Alloc>
float scores_to_likelihoods(std::vector<float, Alloc> & scores);

template<class Alloc>
void scores_to_probs(std::vector<float, Alloc> & scores) {
    float total = scores_to_likelihoods(scores);
    vector_scale(scores.size(), scores.data(), 1.f / total);
}

template<class Alloc>
inline size_t sample_from_scores_overwrite(
        rng_t & rng,
        std::vector<float, Alloc> & scores) {
    float total = scores_to_likelihoods(scores);
    return sample_from_likelihoods(rng, scores, total);
}

template<class Alloc>
inline std::pair<size_t, float> sample_prob_from_scores_overwrite(
        rng_t & rng,
        std::vector<float, Alloc> & scores) {
    float total = scores_to_likelihoods(scores);
    size_t sample = sample_from_likelihoods(rng, scores, total);
    float prob = scores[sample] / total;
    return std::make_pair(sample, prob);
}

// score_from_scores_overwrite(...) = log(prob_from_scores_overwrite(...)),
// this is less succeptible to overflow than prob_from_scores_overwrite
template<class Alloc>
float score_from_scores_overwrite(
        rng_t & rng,
        size_t sample,
        std::vector<float, Alloc> & scores);

template<class Alloc>
inline size_t sample_from_scores(
        rng_t & rng,
        const std::vector<float, Alloc> & scores) {
    std::vector<float, Alloc> scores_copy(scores);
    return sample_from_scores_overwrite(rng, scores_copy);
}

}  // namespace distributions
<|endoftext|>


<commit_before>
#include "../C3_Context.hh"

// Execute application.

template< template< class > class Concurrency, class InstrumentTraits, template< class > class Engine >
inline int C3::Application< Concurrency, InstrumentTraits, Engine >::run( int& argc, char**& argv )
{
    using ContextType    = C3::Context< Concurrency, InstrumentTraits >;
    ContextType& context = ContextType::instance( argc, argv );
    Engine< ContextType > engine;
    while( context.has_tasks() ) engine.process( context.next_task() );
    return context.finalize();
}

// Engine needs to get from context the information it needs to pick out its HDU to process.
// This is probably the frame name.
// With parallel concurrency this is determined at runtime from the MPI rank and the list of frames.
// With serial concurrency this is determined at runtime from input provided by the user.
// Since each concurrency depends on concurrency-related things at runtime it should be determined by that.
// And since that depends on the instrument traits, concurrency needs to know instrument traits (not necessarily inherit from it though).
<commit_msg>To be reverted after debug.<commit_after>
#include "../C3_Context.hh"

// Execute application.

template< template< class > class Concurrency, class InstrumentTraits, template< class > class Engine >
inline int C3::Application< Concurrency, InstrumentTraits, Engine >::run( int& argc, char**& argv )
{
    using ContextType    = C3::Context< Concurrency, InstrumentTraits >;
    ContextType& context = ContextType::instance( argc, argv );
    Engine< ContextType > engine;
//  while( context.has_tasks() ) engine.process( context.next_task() );
    return context.finalize();
}

// Engine needs to get from context the information it needs to pick out its HDU to process.
// This is probably the frame name.
// With parallel concurrency this is determined at runtime from the MPI rank and the list of frames.
// With serial concurrency this is determined at runtime from input provided by the user.
// Since each concurrency depends on concurrency-related things at runtime it should be determined by that.
// And since that depends on the instrument traits, concurrency needs to know instrument traits (not necessarily inherit from it though).
<|endoftext|>


<commit_before>/**
 * @file		icomponent.hpp
 * @brief		Component(Shared Library) interface
 * @author		Byunghun Hwang<bhhwang@nsynapse.com>
 * @date 		2015. 6. 21
 * @details		Component interface class
 */

#ifndef _COSSB_ICOMPONENT_HPP_
#define _COSSB_ICOMPONENT_HPP_

#include <string>
#include "iprofile.hpp"
#include "imessage.hpp"

using namespace std;

namespace cossb {

namespace component {
	enum class status : unsigned int { IDLE=0, RUNNING, STOPPED };
}

namespace interface {

/**
* @brief		component interface class
* @details		base component interface, lifecycle is (setup-run-stop)
* @author		Byunghun Hwang<bhhwang@nsynapse.com>
* @date		2015. 6. 22
*/
class icomponent {

public:
	/**
	 * @brief
	 */
	virtual ~icomponent() {
		if(_profile)
			delete _profile;
	}

	/**
	 * @brief		initialization
	 * @details	this function will be called once when load component
	 * @return		true if it is success
	 */
	virtual bool setup() = 0;

	/**
	 * @brief		start signal comes in, this function will be called
	 * @details
	 */
	virtual bool run() = 0;

	/**
	 * @brief	stop interface
	 * @brief	stop signal comes in, this function will be called
	 */
	virtual bool stop() = 0;

	/**
	 * @brief	message request
	 * @details	if request message comes in, this function will be called
	 */
	virtual void request(imessage* msg) = 0;

	/**
	 * @brief
	 */
	const char* get_name() const {
		return _name.c_str();
	}

	/**
	 * @brief
	 */
	iprofile* get_profile() const {
		return _profile;
	}

	/**
	 * @brief	getting status
	 */
	component::status get_status() { return _status; }

	/**
	 * @brief	set component profile
	 */
	bool set_profile(iprofile* profile, const char* path)
	{
		_profile = profile;
		return _profile->load(path);
	}

protected:
	explicit icomponent(const char* name)
	:_name(name), _profile(nullptr), _status(component::status::IDLE) {

	}

private:
	string _name;
	iprofile* _profile = nullptr;

protected:
	component::status _status;

};

} /* namespace interface */

typedef interface::icomponent*(*create_component)(void);
typedef void(*destroy_component)(void);

#define COMPONENT_EXPORT				extern "C" { cossb::interface::icomponent* create(); void destroy(void); }
#define COMPONENT_INSTANCE(classname)	static classname* _instance = nullptr;
#define COMPONENT_CREATE(classname) 	cossb::interface::icomponent* create(){ \
											if(_instance==nullptr) _instance = new classname(); \
											return _instance; }
#define COMPONENT_DESTROY 				void destroy(){ \
											if(_instance!=nullptr){ \
												delete _instance; _instance=nullptr; }	\
											}
#define COMPONENT(classname) #classname

} /* namespace cossb */

#endif /* _COSSB_ICOMPONENT_HPP_ */
<commit_msg>add log interface variable for component log on console<commit_after>/**
 * @file		icomponent.hpp
 * @brief		Component(Shared Library) interface
 * @author		Byunghun Hwang<bhhwang@nsynapse.com>
 * @date 		2015. 6. 21
 * @details		Component interface class
 */

#ifndef _COSSB_ICOMPONENT_HPP_
#define _COSSB_ICOMPONENT_HPP_

#include <string>
#include "iprofile.hpp"
#include "imessage.hpp"
#include "ilog.hpp"

using namespace std;

namespace cossb {

namespace component {
	enum class status : unsigned int { IDLE=0, RUNNING, STOPPED };
}

namespace interface {

/**
* @brief		component interface class
* @details		base component interface, lifecycle is (setup-run-stop)
* @author		Byunghun Hwang<bhhwang@nsynapse.com>
* @date		2015. 6. 22
*/
class icomponent {

public:
	/**
	 * @brief
	 */
	virtual ~icomponent() {
		if(_profile)
			delete _profile;
	}

	/**
	 * @brief		initialization
	 * @details	this function will be called once when load component
	 * @return		true if it is success
	 */
	virtual bool setup() = 0;

	/**
	 * @brief		start signal comes in, this function will be called
	 * @details
	 */
	virtual bool run() = 0;

	/**
	 * @brief	stop interface
	 * @brief	stop signal comes in, this function will be called
	 */
	virtual bool stop() = 0;

	/**
	 * @brief	message request
	 * @details	if request message comes in, this function will be called
	 */
	virtual void request(imessage* msg) = 0;

	/**
	 * @brief
	 */
	const char* get_name() const {
		return _name.c_str();
	}

	/**
	 * @brief
	 */
	iprofile* get_profile() const {
		return _profile;
	}

	/**
	 * @brief	getting status
	 */
	component::status get_status() { return _status; }

	/**
	 * @brief	set component profile
	 */
	bool set_profile(iprofile* profile, const char* path)
	{
		_profile = profile;
		return _profile->load(path);
	}

protected:
	explicit icomponent(const char* name)
	:_name(name), _profile(nullptr), _status(component::status::IDLE) {

	}

private:
	string _name;

	/**
	 * @brief	component profile interface
	 */
	iprofile* _profile = nullptr;

	/**
	 * @brief	component log interface
	 */
	ilog* _logger = nullptr;

protected:
	component::status _status;

};

} /* namespace interface */

typedef interface::icomponent*(*create_component)(void);
typedef void(*destroy_component)(void);

#define COMPONENT_EXPORT				extern "C" { cossb::interface::icomponent* create(); void destroy(void); }
#define COMPONENT_INSTANCE(classname)	static classname* _instance = nullptr;
#define COMPONENT_CREATE(classname) 	cossb::interface::icomponent* create(){ \
											if(_instance==nullptr) _instance = new classname(); \
											return _instance; }
#define COMPONENT_DESTROY 				void destroy(){ \
											if(_instance!=nullptr){ \
												delete _instance; _instance=nullptr; }	\
											}
#define COMPONENT(classname) #classname

} /* namespace cossb */

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


<commit_before>//======================================================================
//-----------------------------------------------------------------------
/**
 * @file        iutest_port.hpp
 * @brief       portable
 *
 * @author      t.shirayanagi
 * @par         copyright
 * Copyright (C) 2011-2018, Takazumi Shirayanagi\n
 * This software is released under the new BSD License,
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================
#ifndef INCG_IRIS_IUTEST_PORT_HPP_7893F685_A1A9_477A_82E8_BF06237697FF_
#define INCG_IRIS_IUTEST_PORT_HPP_7893F685_A1A9_477A_82E8_BF06237697FF_

//======================================================================
// include
#if defined(__MWERKS__)
#  define _MSL_USING_NAMESPACE
#endif

#include "iutest_internal_defs.hpp"

#if defined(IUTEST_OS_LINUX) || defined(IUTEST_OS_CYGWIN) || defined(IUTEST_OS_MAC)
#  include <unistd.h>
#  include <locale.h>
#endif

#if IUTEST_HAS_FILE_STAT
#  include <sys/stat.h>
#endif

//======================================================================
// define
#if !defined(IUTEST_MAX_PATH)
#  if   defined(MAX_PATH) && MAX_PATH
#    define IUTEST_MAX_PATH MAX_PATH
#  elif defined(PATH_MAX) && PATH_MAX
#    define IUTEST_MAX_PATH PATH_MAX
#  elif defined(FILENAME_MAX) && FILENAME_MAX
#    define IUTEST_MAX_PATH FILENAME_MAX
#  else
#    define IUTEST_MAX_PATH 1024
#  endif
#endif

/**
 * @brief   ログメッセージストリーム
*/
#define IUTEST_LOG_(level)          \
    ::iutest::detail::IUTestLog(    \
        ::iutest::detail::IUTestLog::LOG_##level, __FILE__, __LINE__).GetStream()

/**
 * @brief   内部エラーチェック
*/
#define IUTEST_CHECK_(condition)                \
    IUTEST_AMBIGUOUS_ELSE_BLOCKER_              \
    if( !::iutest::detail::IsTrue(condition) )  \
        IUTEST_LOG_(FATAL) << "Condition " #condition " failed. "

namespace iutest {

#ifdef IUTEST_OS_NACL
namespace nacl
{

/**
 * @brief   printf
*/
void vprint_message(const char *fmt, va_list va);
void print_message(const char *fmt, ...);

}
#endif

namespace internal {
namespace posix
{

const char* GetEnv(const char* name);
int PutEnv(const char* expr);
int SetEnv(const char* name, const char* value, int overwrite);

const char* GetCWD(char* buf, size_t length);
::std::string GetCWD();

void SleepMillisec(unsigned int millisec);

#if defined(IUTEST_OS_WINDOWS_MOBILE)
void Abort();
#else
IUTEST_ATTRIBUTE_NORETURN_ void Abort();
inline void Abort() { abort(); }
#endif

#if IUTEST_HAS_FILENO

#if defined(_MSC_VER)
inline int Fileno(FILE* fp) { return _fileno(fp); }
#else
inline int Fileno(FILE* fp) { return fileno(fp); }
#endif

#else

inline int Fileno(FILE* fp) { return -1; }

#endif

#if IUTEST_HAS_FILE_STAT

#if defined(IUTEST_OS_WINDOWS) && !defined(IUTEST_OS_WINDOWS_WINE)

typedef struct _stat StatStruct;

inline int Stat(FILE* fp, StatStruct* buf) { return _fstat(Fileno(fp), buf); }
inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
inline bool IsDir(const StatStruct& st) { return (st.st_mode & _S_IFDIR) != 0; }

#else

typedef struct stat StatStruct;

inline int Stat(FILE* fp, StatStruct* buf) { return fstat(Fileno(fp), buf); }
inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }

#endif

#endif

}   // end of namespace posix

inline void SleepMilliseconds(int n) { posix::SleepMillisec(static_cast<unsigned int>(n)); }

}   // end of namespace internal

namespace detail
{

namespace posix = internal::posix;

/**
 * @brief   パス区切り文字の取得
*/
char GetPathSeparator() IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   パス区切り文字かどうか
*/
bool IsPathSeparator(char c) IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   パス区切り文字かどうか
*/
bool IsAltPathSeparator(char c) IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   一番後ろのパスセパレータのアドレスを取得
*/
const char* FindLastPathSeparator(const char* path, size_t length) IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   環境変数の設定
*/
bool SetEnvironmentVariable(const char* name, const char* value);

/**
 * @brief   環境変数の取得
 * @param [in]  name    = 環境変数名
 * @param [out] buf     = 出力バッファ
 * @return  成否
*/
bool GetEnvironmentVariable(const char* name, char* buf, size_t size);

#if !defined(IUTEST_NO_FUNCTION_TEMPLATE_ORDERING)

template<size_t SIZE>
inline bool GetEnvironmentVariable(const char* name, char (&buf)[SIZE])
{
return GetEnvironmentVariable(name, buf, SIZE);
}

#endif

/**
 * @brief   環境変数の取得
 * @param [in]  name    = 環境変数名
 * @param [out] var     = 出力文字列
 * @return  成否
 */
bool IUTEST_ATTRIBUTE_UNUSED_ GetEnvironmentVariable(const char* name, ::std::string& var);

/**
 * @brief   環境変数の取得
 * @param [in]  name    = 環境変数名
 * @param [out] var     = 出力数値
 * @return  成否
 */
bool IUTEST_ATTRIBUTE_UNUSED_ GetEnvironmentInt(const char* name, int& var);

#if defined(IUTEST_OS_WINDOWS)
namespace win
{

    /**
     * @brief   文字列変換
     */
    ::std::string IUTEST_ATTRIBUTE_UNUSED_ WideStringToMultiByteString(const wchar_t* wide_c_str);

    /**
     * @brief   HRESULT のエラー文字列を取得
     * @param [in]  hr  = エラー値
     * @return  文字列
     */
    ::std::string IUTEST_ATTRIBUTE_UNUSED_ GetHResultString(HRESULT hr);

}   // end of namespace win
#endif

/**
 * @brief   ログ
 */
class IUTestLog
{
public:
    enum Level
    {
          LOG_INFO
        , LOG_WARNING
        , LOG_ERROR
        , LOG_FATAL
        , LOG_LEVEL_NUM
    };
public:
    IUTestLog(Level level, const char* file, int line);

    ~IUTestLog();

public:
    iu_stringstream& GetStream() { return m_stream; }

public:
    static int GetCount(Level level) { return GetCountTable().count[level]; }
    static bool HasWarning() { return GetCount(LOG_WARNING) > 0; }
    static bool HasError() { return GetCount(LOG_ERROR) > 0 || GetCount(LOG_FATAL) > 0; }

private:
    struct Count
    {
        int count[LOG_LEVEL_NUM];
    };

    static Count& GetCountTable() { static Count count = { {0} }; return count; }
    static void CountUp(int level);

private:
    const Level kLevel;
    iu_stringstream m_stream;

    IUTEST_PP_DISALLOW_COPY_AND_ASSIGN(IUTestLog);
};

#if IUTEST_HAS_STREAM_BUFFER

/**
 * @brief   stream buffer
*/
template<int SIZE=BUFSIZ>
class IUStreamBuffer
{
public:
    IUTEST_PRAGMA_CRT_SECURE_WARN_DISABLE_BEGIN()

    explicit IUStreamBuffer(FILE* fp)
        : m_fp(fp)
    {
        m_buf[0] = '\0';
        fflush(fp);
        setvbuf(fp, m_buf, _IOFBF, SIZE);
    }

    ~IUStreamBuffer()
    {
        fflush(m_fp);
        setbuf(m_fp, NULL);
    }

    IUTEST_PRAGMA_CRT_SECURE_WARN_DISABLE_END()

public:
    ::std::string GetStreamString() { return m_buf; }

private:
    FILE* m_fp;
    char m_buf[SIZE];
};

/**
* @brief    stream capture
*/

#endif

}   // end of namespace detail
}   // end of namespace iutest

#if !IUTEST_HAS_LIB
#  include "../impl/iutest_port.ipp"
#endif

#endif // INCG_IRIS_IUTEST_PORT_HPP_7893F685_A1A9_477A_82E8_BF06237697FF_
<commit_msg>fix unused warning<commit_after>//======================================================================
//-----------------------------------------------------------------------
/**
 * @file        iutest_port.hpp
 * @brief       portable
 *
 * @author      t.shirayanagi
 * @par         copyright
 * Copyright (C) 2011-2018, Takazumi Shirayanagi\n
 * This software is released under the new BSD License,
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================
#ifndef INCG_IRIS_IUTEST_PORT_HPP_7893F685_A1A9_477A_82E8_BF06237697FF_
#define INCG_IRIS_IUTEST_PORT_HPP_7893F685_A1A9_477A_82E8_BF06237697FF_

//======================================================================
// include
#if defined(__MWERKS__)
#  define _MSL_USING_NAMESPACE
#endif

#include "iutest_internal_defs.hpp"

#if defined(IUTEST_OS_LINUX) || defined(IUTEST_OS_CYGWIN) || defined(IUTEST_OS_MAC)
#  include <unistd.h>
#  include <locale.h>
#endif

#if IUTEST_HAS_FILE_STAT
#  include <sys/stat.h>
#endif

//======================================================================
// define
#if !defined(IUTEST_MAX_PATH)
#  if   defined(MAX_PATH) && MAX_PATH
#    define IUTEST_MAX_PATH MAX_PATH
#  elif defined(PATH_MAX) && PATH_MAX
#    define IUTEST_MAX_PATH PATH_MAX
#  elif defined(FILENAME_MAX) && FILENAME_MAX
#    define IUTEST_MAX_PATH FILENAME_MAX
#  else
#    define IUTEST_MAX_PATH 1024
#  endif
#endif

/**
 * @brief   ログメッセージストリーム
*/
#define IUTEST_LOG_(level)          \
    ::iutest::detail::IUTestLog(    \
        ::iutest::detail::IUTestLog::LOG_##level, __FILE__, __LINE__).GetStream()

/**
 * @brief   内部エラーチェック
*/
#define IUTEST_CHECK_(condition)                \
    IUTEST_AMBIGUOUS_ELSE_BLOCKER_              \
    if( !::iutest::detail::IsTrue(condition) )  \
        IUTEST_LOG_(FATAL) << "Condition " #condition " failed. "

namespace iutest {

#ifdef IUTEST_OS_NACL
namespace nacl
{

/**
 * @brief   printf
*/
void vprint_message(const char *fmt, va_list va);
void print_message(const char *fmt, ...);

}
#endif

namespace internal {
namespace posix
{

const char* GetEnv(const char* name);
int PutEnv(const char* expr);
int SetEnv(const char* name, const char* value, int overwrite);

const char* GetCWD(char* buf, size_t length);
::std::string GetCWD();

void SleepMillisec(unsigned int millisec);

#if defined(IUTEST_OS_WINDOWS_MOBILE)
void Abort();
#else
IUTEST_ATTRIBUTE_NORETURN_ void Abort();
inline void Abort() { abort(); }
#endif

#if IUTEST_HAS_FILENO

#if defined(_MSC_VER)
inline int Fileno(FILE* fp) { return _fileno(fp); }
#else
inline int Fileno(FILE* fp) { return fileno(fp); }
#endif

#else

inline int Fileno(FILE*) { return -1; }

#endif

#if IUTEST_HAS_FILE_STAT

#if defined(IUTEST_OS_WINDOWS) && !defined(IUTEST_OS_WINDOWS_WINE)

typedef struct _stat StatStruct;

inline int Stat(FILE* fp, StatStruct* buf) { return _fstat(Fileno(fp), buf); }
inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
inline bool IsDir(const StatStruct& st) { return (st.st_mode & _S_IFDIR) != 0; }

#else

typedef struct stat StatStruct;

inline int Stat(FILE* fp, StatStruct* buf) { return fstat(Fileno(fp), buf); }
inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }

#endif

#endif

}   // end of namespace posix

inline void SleepMilliseconds(int n) { posix::SleepMillisec(static_cast<unsigned int>(n)); }

}   // end of namespace internal

namespace detail
{

namespace posix = internal::posix;

/**
 * @brief   パス区切り文字の取得
*/
char GetPathSeparator() IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   パス区切り文字かどうか
*/
bool IsPathSeparator(char c) IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   パス区切り文字かどうか
*/
bool IsAltPathSeparator(char c) IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   一番後ろのパスセパレータのアドレスを取得
*/
const char* FindLastPathSeparator(const char* path, size_t length) IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   環境変数の設定
*/
bool SetEnvironmentVariable(const char* name, const char* value);

/**
 * @brief   環境変数の取得
 * @param [in]  name    = 環境変数名
 * @param [out] buf     = 出力バッファ
 * @return  成否
*/
bool GetEnvironmentVariable(const char* name, char* buf, size_t size);

#if !defined(IUTEST_NO_FUNCTION_TEMPLATE_ORDERING)

template<size_t SIZE>
inline bool GetEnvironmentVariable(const char* name, char (&buf)[SIZE])
{
return GetEnvironmentVariable(name, buf, SIZE);
}

#endif

/**
 * @brief   環境変数の取得
 * @param [in]  name    = 環境変数名
 * @param [out] var     = 出力文字列
 * @return  成否
 */
bool IUTEST_ATTRIBUTE_UNUSED_ GetEnvironmentVariable(const char* name, ::std::string& var);

/**
 * @brief   環境変数の取得
 * @param [in]  name    = 環境変数名
 * @param [out] var     = 出力数値
 * @return  成否
 */
bool IUTEST_ATTRIBUTE_UNUSED_ GetEnvironmentInt(const char* name, int& var);

#if defined(IUTEST_OS_WINDOWS)
namespace win
{

    /**
     * @brief   文字列変換
     */
    ::std::string IUTEST_ATTRIBUTE_UNUSED_ WideStringToMultiByteString(const wchar_t* wide_c_str);

    /**
     * @brief   HRESULT のエラー文字列を取得
     * @param [in]  hr  = エラー値
     * @return  文字列
     */
    ::std::string IUTEST_ATTRIBUTE_UNUSED_ GetHResultString(HRESULT hr);

}   // end of namespace win
#endif

/**
 * @brief   ログ
 */
class IUTestLog
{
public:
    enum Level
    {
          LOG_INFO
        , LOG_WARNING
        , LOG_ERROR
        , LOG_FATAL
        , LOG_LEVEL_NUM
    };
public:
    IUTestLog(Level level, const char* file, int line);

    ~IUTestLog();

public:
    iu_stringstream& GetStream() { return m_stream; }

public:
    static int GetCount(Level level) { return GetCountTable().count[level]; }
    static bool HasWarning() { return GetCount(LOG_WARNING) > 0; }
    static bool HasError() { return GetCount(LOG_ERROR) > 0 || GetCount(LOG_FATAL) > 0; }

private:
    struct Count
    {
        int count[LOG_LEVEL_NUM];
    };

    static Count& GetCountTable() { static Count count = { {0} }; return count; }
    static void CountUp(int level);

private:
    const Level kLevel;
    iu_stringstream m_stream;

    IUTEST_PP_DISALLOW_COPY_AND_ASSIGN(IUTestLog);
};

#if IUTEST_HAS_STREAM_BUFFER

/**
 * @brief   stream buffer
*/
template<int SIZE=BUFSIZ>
class IUStreamBuffer
{
public:
    IUTEST_PRAGMA_CRT_SECURE_WARN_DISABLE_BEGIN()

    explicit IUStreamBuffer(FILE* fp)
        : m_fp(fp)
    {
        m_buf[0] = '\0';
        fflush(fp);
        setvbuf(fp, m_buf, _IOFBF, SIZE);
    }

    ~IUStreamBuffer()
    {
        fflush(m_fp);
        setbuf(m_fp, NULL);
    }

    IUTEST_PRAGMA_CRT_SECURE_WARN_DISABLE_END()

public:
    ::std::string GetStreamString() { return m_buf; }

private:
    FILE* m_fp;
    char m_buf[SIZE];
};

/**
* @brief    stream capture
*/

#endif

}   // end of namespace detail
}   // end of namespace iutest

#if !IUTEST_HAS_LIB
#  include "../impl/iutest_port.ipp"
#endif

#endif // INCG_IRIS_IUTEST_PORT_HPP_7893F685_A1A9_477A_82E8_BF06237697FF_
<|endoftext|>


<commit_before>/*

Copyright (c) 2005, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_IP_FILTER_HPP
#define TORRENT_IP_FILTER_HPP

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/limits.hpp>
#include <boost/utility.hpp>
#include <boost/tuple/tuple.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/config.hpp"
#include "libtorrent/socket.hpp"
#include <set>
#include <iostream>

namespace libtorrent
{

inline bool operator<=(address const& lhs
	, address const& rhs)
{
	return lhs < rhs || lhs == rhs;
}

template <class Addr>
struct ip_range
{
	Addr first;
	Addr last;
	int flags;
};

namespace detail
{

	template<class Addr>
	Addr zero()
	{
		typename Addr::bytes_type zero;
		std::fill(zero.begin(), zero.end(), 0);
		return Addr(zero);
	}

	template<>
	inline boost::uint16_t zero<boost::uint16_t>() { return 0; }

	template<class Addr>
	Addr plus_one(Addr const& a)
	{
		typename Addr::bytes_type tmp(a.to_bytes());
		typedef typename Addr::bytes_type::reverse_iterator iter;
		for (iter i = tmp.rbegin()
			, end(tmp.rend()); i != end; ++i)
		{
			if (*i < (std::numeric_limits<typename iter::value_type>::max)())
			{
				*i += 1;
				break;
			}
			*i = 0;
		}
		return Addr(tmp);
	}

	inline boost::uint16_t plus_one(boost::uint16_t val) { return val + 1; }

	template<class Addr>
	Addr minus_one(Addr const& a)
	{
		typename Addr::bytes_type tmp(a.to_bytes());
		typedef typename Addr::bytes_type::reverse_iterator iter;
		for (iter i = tmp.rbegin()
			, end(tmp.rend()); i != end; ++i)
		{
			if (*i > 0)
			{
				*i -= 1;
				break;
			}
			*i = (std::numeric_limits<typename iter::value_type>::max)();
		}
		return Addr(tmp);
	}

	inline boost::uint16_t minus_one(boost::uint16_t val) { return val - 1; }

	template<class Addr>
	Addr max_addr()
	{
		typename Addr::bytes_type tmp;
		std::fill(tmp.begin(), tmp.end()
			, (std::numeric_limits<typename Addr::bytes_type::value_type>::max)());
		return Addr(tmp);
	}

	template<>
	inline boost::uint16_t max_addr<boost::uint16_t>()
	{ return std::numeric_limits<boost::uint16_t>::max(); }

	// this is the generic implementation of
	// a filter for a specific address type.
	// it works with IPv4 and IPv6
	template<class Addr>
	class filter_impl
	{
	public:

		filter_impl()
		{
			// make the entire ip-range non-blocked
			m_access_list.insert(range(zero<Addr>(), 0));
		}

		void add_rule(Addr first, Addr last, int flags)
		{
			using boost::next;
			using boost::prior;

			assert(!m_access_list.empty());
			assert(first < last || first == last);

			typename range_t::iterator i = m_access_list.upper_bound(first);
			typename range_t::iterator j = m_access_list.upper_bound(last);

			if (i != m_access_list.begin()) --i;

			assert(j != m_access_list.begin());
			assert(j != i);

			int first_access = i->access;
			int last_access = prior(j)->access;

			if (i->start != first && first_access != flags)
			{
				i = m_access_list.insert(i, range(first, flags));
			}
			else if (i != m_access_list.begin() && prior(i)->access == flags)
			{
				--i;
				first_access = i->access;
			}
			assert(!m_access_list.empty());
			assert(i != m_access_list.end());

			if (i != j) m_access_list.erase(next(i), j);
			if (i->start == first)
			{
				// we can do this const-cast because we know that the new
				// start address will keep the set correctly ordered
				const_cast<Addr&>(i->start) = first;
				const_cast<int&>(i->access) = flags;
			}
			else if (first_access != flags)
			{
				m_access_list.insert(i, range(first, flags));
			}

			if ((j != m_access_list.end()
					&& minus_one(j->start) != last)
				|| (j == m_access_list.end()
					&& last != max_addr<Addr>()))
			{
				assert(j == m_access_list.end() || last < minus_one(j->start));
				if (last_access != flags)
					j = m_access_list.insert(j, range(plus_one(last), last_access));
			}

			if (j != m_access_list.end() && j->access == flags) m_access_list.erase(j);
			assert(!m_access_list.empty());
		}

		int access(Addr const& addr) const
		{
			assert(!m_access_list.empty());
			typename range_t::const_iterator i = m_access_list.upper_bound(addr);
			if (i != m_access_list.begin()) --i;
			assert(i != m_access_list.end());
			assert(i->start <= addr && (boost::next(i) == m_access_list.end()
				|| addr < boost::next(i)->start));
			return i->access;
		}

		std::vector<ip_range<Addr> > export_filter() const
		{
			std::vector<ip_range<Addr> > ret;
			ret.reserve(m_access_list.size());

			for (typename range_t::const_iterator i = m_access_list.begin()
				, end(m_access_list.end()); i != end;)
			{
				ip_range<Addr> r;
				r.first = i->start;
				r.flags = i->access;

				++i;
				if (i == end)
					r.last = max_addr<Addr>();
				else
					r.last = minus_one(i->start);

				ret.push_back(r);
			}
			return ret;
		}

	private:

		struct range
		{
			range(Addr addr, int access = 0): start(addr), access(access) {}
			bool operator<(range const& r) const
			{ return start < r.start; }
			bool operator<(Addr const& a) const
			{ return start < a; }
			Addr start;
			// the end of the range is implicit
			// and given by the next entry in the set
			int access;
		};

		typedef std::set<range> range_t;
		range_t m_access_list;

	};

}

class TORRENT_EXPORT ip_filter
{
public:

	enum access_flags
	{
		blocked = 1
	};

	// both addresses MUST be of the same type (i.e. both must
	// be either IPv4 or both must be IPv6)
	void add_rule(address first, address last, int flags);
	int access(address const& addr) const;

	typedef boost::tuple<std::vector<ip_range<address_v4> >
		, std::vector<ip_range<address_v6> > > filter_tuple_t;

	filter_tuple_t export_filter() const;

//	void print() const;

private:

	detail::filter_impl<address_v4> m_filter4;
	detail::filter_impl<address_v6> m_filter6;
};

class TORRENT_EXPORT port_filter
{
public:

	enum access_flags
	{
		blocked = 1
	};

	void add_rule(boost::uint16_t first, boost::uint16_t last, int flags);
	int access(boost::uint16_t port) const;

private:

	detail::filter_impl<boost::uint16_t> m_filter;

};

}

#endif

<commit_msg>fix for msvc<commit_after>/*

Copyright (c) 2005, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_IP_FILTER_HPP
#define TORRENT_IP_FILTER_HPP

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/limits.hpp>
#include <boost/utility.hpp>
#include <boost/tuple/tuple.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/config.hpp"
#include "libtorrent/socket.hpp"
#include <set>
#include <iostream>

namespace libtorrent
{

inline bool operator<=(address const& lhs
	, address const& rhs)
{
	return lhs < rhs || lhs == rhs;
}

template <class Addr>
struct ip_range
{
	Addr first;
	Addr last;
	int flags;
};

namespace detail
{

	template<class Addr>
	Addr zero()
	{
		typename Addr::bytes_type zero;
		std::fill(zero.begin(), zero.end(), 0);
		return Addr(zero);
	}

	template<>
	inline boost::uint16_t zero<boost::uint16_t>() { return 0; }

	template<class Addr>
	Addr plus_one(Addr const& a)
	{
		typename Addr::bytes_type tmp(a.to_bytes());
		typedef typename Addr::bytes_type::reverse_iterator iter;
		for (iter i = tmp.rbegin()
			, end(tmp.rend()); i != end; ++i)
		{
			if (*i < (std::numeric_limits<typename iter::value_type>::max)())
			{
				*i += 1;
				break;
			}
			*i = 0;
		}
		return Addr(tmp);
	}

	inline boost::uint16_t plus_one(boost::uint16_t val) { return val + 1; }

	template<class Addr>
	Addr minus_one(Addr const& a)
	{
		typename Addr::bytes_type tmp(a.to_bytes());
		typedef typename Addr::bytes_type::reverse_iterator iter;
		for (iter i = tmp.rbegin()
			, end(tmp.rend()); i != end; ++i)
		{
			if (*i > 0)
			{
				*i -= 1;
				break;
			}
			*i = (std::numeric_limits<typename iter::value_type>::max)();
		}
		return Addr(tmp);
	}

	inline boost::uint16_t minus_one(boost::uint16_t val) { return val - 1; }

	template<class Addr>
	Addr max_addr()
	{
		typename Addr::bytes_type tmp;
		std::fill(tmp.begin(), tmp.end()
			, (std::numeric_limits<typename Addr::bytes_type::value_type>::max)());
		return Addr(tmp);
	}

	template<>
	inline boost::uint16_t max_addr<boost::uint16_t>()
	{ return (std::numeric_limits<boost::uint16_t>::max)(); }

	// this is the generic implementation of
	// a filter for a specific address type.
	// it works with IPv4 and IPv6
	template<class Addr>
	class filter_impl
	{
	public:

		filter_impl()
		{
			// make the entire ip-range non-blocked
			m_access_list.insert(range(zero<Addr>(), 0));
		}

		void add_rule(Addr first, Addr last, int flags)
		{
			using boost::next;
			using boost::prior;

			assert(!m_access_list.empty());
			assert(first < last || first == last);

			typename range_t::iterator i = m_access_list.upper_bound(first);
			typename range_t::iterator j = m_access_list.upper_bound(last);

			if (i != m_access_list.begin()) --i;

			assert(j != m_access_list.begin());
			assert(j != i);

			int first_access = i->access;
			int last_access = prior(j)->access;

			if (i->start != first && first_access != flags)
			{
				i = m_access_list.insert(i, range(first, flags));
			}
			else if (i != m_access_list.begin() && prior(i)->access == flags)
			{
				--i;
				first_access = i->access;
			}
			assert(!m_access_list.empty());
			assert(i != m_access_list.end());

			if (i != j) m_access_list.erase(next(i), j);
			if (i->start == first)
			{
				// we can do this const-cast because we know that the new
				// start address will keep the set correctly ordered
				const_cast<Addr&>(i->start) = first;
				const_cast<int&>(i->access) = flags;
			}
			else if (first_access != flags)
			{
				m_access_list.insert(i, range(first, flags));
			}

			if ((j != m_access_list.end()
					&& minus_one(j->start) != last)
				|| (j == m_access_list.end()
					&& last != max_addr<Addr>()))
			{
				assert(j == m_access_list.end() || last < minus_one(j->start));
				if (last_access != flags)
					j = m_access_list.insert(j, range(plus_one(last), last_access));
			}

			if (j != m_access_list.end() && j->access == flags) m_access_list.erase(j);
			assert(!m_access_list.empty());
		}

		int access(Addr const& addr) const
		{
			assert(!m_access_list.empty());
			typename range_t::const_iterator i = m_access_list.upper_bound(addr);
			if (i != m_access_list.begin()) --i;
			assert(i != m_access_list.end());
			assert(i->start <= addr && (boost::next(i) == m_access_list.end()
				|| addr < boost::next(i)->start));
			return i->access;
		}

		std::vector<ip_range<Addr> > export_filter() const
		{
			std::vector<ip_range<Addr> > ret;
			ret.reserve(m_access_list.size());

			for (typename range_t::const_iterator i = m_access_list.begin()
				, end(m_access_list.end()); i != end;)
			{
				ip_range<Addr> r;
				r.first = i->start;
				r.flags = i->access;

				++i;
				if (i == end)
					r.last = max_addr<Addr>();
				else
					r.last = minus_one(i->start);

				ret.push_back(r);
			}
			return ret;
		}

	private:

		struct range
		{
			range(Addr addr, int access = 0): start(addr), access(access) {}
			bool operator<(range const& r) const
			{ return start < r.start; }
			bool operator<(Addr const& a) const
			{ return start < a; }
			Addr start;
			// the end of the range is implicit
			// and given by the next entry in the set
			int access;
		};

		typedef std::set<range> range_t;
		range_t m_access_list;

	};

}

class TORRENT_EXPORT ip_filter
{
public:

	enum access_flags
	{
		blocked = 1
	};

	// both addresses MUST be of the same type (i.e. both must
	// be either IPv4 or both must be IPv6)
	void add_rule(address first, address last, int flags);
	int access(address const& addr) const;

	typedef boost::tuple<std::vector<ip_range<address_v4> >
		, std::vector<ip_range<address_v6> > > filter_tuple_t;

	filter_tuple_t export_filter() const;

//	void print() const;

private:

	detail::filter_impl<address_v4> m_filter4;
	detail::filter_impl<address_v6> m_filter6;
};

class TORRENT_EXPORT port_filter
{
public:

	enum access_flags
	{
		blocked = 1
	};

	void add_rule(boost::uint16_t first, boost::uint16_t last, int flags);
	int access(boost::uint16_t port) const;

private:

	detail::filter_impl<boost::uint16_t> m_filter;

};

}

#endif

<|endoftext|>


<commit_before>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#include <stdexcept>
#include "VorbisClip.hpp"
#include "Audio.hpp"
#include "mixer/Stream.hpp"
#include "mixer/Source.hpp"
#include "utils/Utils.hpp"

#include "stb_vorbis.c"

namespace ouzel
{
    namespace audio
    {
        class VorbisData;

        class VorbisSource final: public mixer::Stream
        {
        public:
            VorbisSource(VorbisData& vorbisData);

            ~VorbisSource()
            {
                if (vorbisStream)
                    stb_vorbis_close(vorbisStream);
            }

            void reset() override
            {
                stb_vorbis_seek_start(vorbisStream);
            }

            void getData(uint32_t frames, std::vector<float>& samples) override;

        private:
            stb_vorbis* vorbisStream = nullptr;
            std::vector<float> data;
        };

        class VorbisData final: public mixer::Source
        {
        public:
            VorbisData(const std::vector<uint8_t>& initData):
                data(initData)
            {
                stb_vorbis* vorbisStream = stb_vorbis_open_memory(data.data(), static_cast<int>(data.size()), nullptr, nullptr);

                if (!vorbisStream)
                    throw std::runtime_error("Failed to load Vorbis stream");

                stb_vorbis_info info = stb_vorbis_get_info(vorbisStream);

                channels = static_cast<uint16_t>(info.channels);
                sampleRate = info.sample_rate;

                stb_vorbis_close(vorbisStream);
            }

            const std::vector<uint8_t>& getData() const { return data; }

            std::unique_ptr<mixer::Stream> createStream() override
            {
                return std::unique_ptr<mixer::Stream>(new VorbisSource(*this));
            }

        private:
            std::vector<uint8_t> data;
        };

        VorbisSource::VorbisSource(VorbisData& vorbisData):
            Stream(vorbisData)
        {
            vorbisStream = stb_vorbis_open_memory(vorbisData.getData().data(),
                                                  static_cast<int>(vorbisData.getData().size()),
                                                  nullptr, nullptr);
        }

        void VorbisSource::getData(uint32_t frames, std::vector<float>& samples)
        {
            uint32_t neededSize = frames * source.getChannels();
            samples.resize(neededSize);

            uint32_t copyFrames = 0;

            if (neededSize > 0)
            {
                if (vorbisStream->eof)
                    reset();

                data.resize(neededSize);

                int resultFrames = stb_vorbis_get_samples_float_interleaved(vorbisStream, source.getChannels(),
                                                                            data.data(), static_cast<int>(data.size()));
                copyFrames = static_cast<uint32_t>(resultFrames);

                switch (source.getChannels())
                {
                    case 1:
                        samples = data;
                        break;
                    case 2:
                        for (uint32_t frame = 0; frame < frames; ++frame)
                        {
                            samples[0 * frames + frame] = data[frame * 2 + 0];
                            samples[1 * frames + frame] = data[frame * 2 + 1];
                        }
                        break;
                    case 4:
                        for (uint32_t frame = 0; frame < frames; ++frame)
                        {
                            samples[0 * frames + frame] = data[frame * 4 + 0];
                            samples[1 * frames + frame] = data[frame * 4 + 1];
                            samples[2 * frames + frame] = data[frame * 4 + 2];
                            samples[3 * frames + frame] = data[frame * 4 + 3];
                        }
                        break;
                    case 6:
                        for (uint32_t frame = 0; frame < frames; ++frame)
                        {
                            samples[0 * frames + frame] = data[frame * 4 + 0];
                            samples[1 * frames + frame] = data[frame * 4 + 2];
                            samples[2 * frames + frame] = data[frame * 4 + 1];
                            samples[3 * frames + frame] = data[frame * 4 + 5];
                            samples[4 * frames + frame] = data[frame * 4 + 3];
                            samples[5 * frames + frame] = data[frame * 4 + 4];
                        }
                        break;
                    default:
                        throw std::runtime_error("Unsupported channel count");
                }
            }

            if (vorbisStream->eof)
            {
                playing = false; // TODO: fire event
                reset();
            }

            for (uint32_t channel = 0; channel < source.getChannels(); ++channel)
                for (uint32_t frame = copyFrames; frame < frames; ++frame)
                    samples[channel * frames + frame] = 0.0F;
        }

        VorbisClip::VorbisClip(Audio& initAudio, const std::vector<uint8_t>& initData):
            Sound(initAudio, initAudio.initSource([initData](){
                return std::unique_ptr<mixer::Source>(new VorbisData(initData));
            }))
        {
        }
    } // namespace audio
} // namespace ouzel
<commit_msg>Get planar audio from Vorbis instead of interleaved<commit_after>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#include <stdexcept>
#include "VorbisClip.hpp"
#include "Audio.hpp"
#include "mixer/Stream.hpp"
#include "mixer/Source.hpp"
#include "utils/Utils.hpp"

#include "stb_vorbis.c"

namespace ouzel
{
    namespace audio
    {
        class VorbisData;

        class VorbisSource final: public mixer::Stream
        {
        public:
            VorbisSource(VorbisData& vorbisData);

            ~VorbisSource()
            {
                if (vorbisStream)
                    stb_vorbis_close(vorbisStream);
            }

            void reset() override
            {
                stb_vorbis_seek_start(vorbisStream);
            }

            void getData(uint32_t frames, std::vector<float>& samples) override;

        private:
            stb_vorbis* vorbisStream = nullptr;
            std::vector<float> data;
        };

        class VorbisData final: public mixer::Source
        {
        public:
            VorbisData(const std::vector<uint8_t>& initData):
                data(initData)
            {
                stb_vorbis* vorbisStream = stb_vorbis_open_memory(data.data(), static_cast<int>(data.size()), nullptr, nullptr);

                if (!vorbisStream)
                    throw std::runtime_error("Failed to load Vorbis stream");

                stb_vorbis_info info = stb_vorbis_get_info(vorbisStream);

                channels = static_cast<uint16_t>(info.channels);
                sampleRate = info.sample_rate;

                stb_vorbis_close(vorbisStream);
            }

            const std::vector<uint8_t>& getData() const { return data; }

            std::unique_ptr<mixer::Stream> createStream() override
            {
                return std::unique_ptr<mixer::Stream>(new VorbisSource(*this));
            }

        private:
            std::vector<uint8_t> data;
        };

        VorbisSource::VorbisSource(VorbisData& vorbisData):
            Stream(vorbisData)
        {
            vorbisStream = stb_vorbis_open_memory(vorbisData.getData().data(),
                                                  static_cast<int>(vorbisData.getData().size()),
                                                  nullptr, nullptr);
        }

        void VorbisSource::getData(uint32_t frames, std::vector<float>& samples)
        {
            uint32_t neededSize = frames * source.getChannels();
            samples.resize(neededSize);

            uint32_t copyFrames = 0;

            if (neededSize > 0)
            {
                if (vorbisStream->eof)
                    reset();

                data.resize(neededSize);

                std::vector<float*> channelData(source.getChannels());
                for (uint32_t channel = 0; channel < source.getChannels(); ++channel)
                    channelData[channel] = &data[channel * frames];

                int resultFrames = stb_vorbis_get_samples_float(vorbisStream, source.getChannels(),
                                                                channelData.data(), static_cast<int>(frames));
                copyFrames = static_cast<uint32_t>(resultFrames);

                switch (source.getChannels())
                {
                    case 1:
                        samples = data;
                        break;
                    case 2:
                        for (uint32_t frame = 0; frame < frames; ++frame)
                        {
                            samples[0 * frames + frame] = channelData[0][frame];
                            samples[1 * frames + frame] = channelData[1][frame];
                        }
                        break;
                    case 4:
                        for (uint32_t frame = 0; frame < frames; ++frame)
                        {
                            samples[0 * frames + frame] = channelData[0][frame];
                            samples[1 * frames + frame] = channelData[1][frame];
                            samples[2 * frames + frame] = channelData[2][frame];
                            samples[3 * frames + frame] = channelData[3][frame];
                        }
                        break;
                    case 6:
                        for (uint32_t frame = 0; frame < frames; ++frame)
                        {
                            samples[0 * frames + frame] = channelData[0][frame];
                            samples[1 * frames + frame] = channelData[2][frame];
                            samples[2 * frames + frame] = channelData[1][frame];
                            samples[3 * frames + frame] = channelData[5][frame];
                            samples[4 * frames + frame] = channelData[3][frame];
                            samples[5 * frames + frame] = channelData[4][frame];
                        }
                        break;
                    default:
                        throw std::runtime_error("Unsupported channel count");
                }
            }

            if (vorbisStream->eof)
            {
                playing = false; // TODO: fire event
                reset();
            }

            for (uint32_t channel = 0; channel < source.getChannels(); ++channel)
                for (uint32_t frame = copyFrames; frame < frames; ++frame)
                    samples[channel * frames + frame] = 0.0F;
        }

        VorbisClip::VorbisClip(Audio& initAudio, const std::vector<uint8_t>& initData):
            Sound(initAudio, initAudio.initSource([initData](){
                return std::unique_ptr<mixer::Source>(new VorbisData(initData));
            }))
        {
        }
    } // namespace audio
} // namespace ouzel
<|endoftext|>


<commit_before>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <cstring>
#include "core/CompileConfig.h"
#include "Texture.h"
#include "core/Engine.h"
#include "Renderer.h"
#include "Image.h"
#include "utils/Utils.h"
#include "math/MathUtils.h"

namespace ouzel
{
    namespace graphics
    {
        Texture::Texture()
        {

        }

        Texture::~Texture()
        {

        }

        void Texture::free()
        {
            levels.clear();
            uploadData.levels.clear();

            ready = false;
        }

        bool Texture::init(const Size2& newSize, bool newDynamic, bool newMipmaps, bool newRenderTarget)
        {
            free();

            size = newSize;
            dynamic = newDynamic;
            mipmaps = newMipmaps;
            renderTarget = newRenderTarget;

            dirty = true;

            sharedEngine->getRenderer()->scheduleUpdate(shared_from_this());

            return true;
        }

        bool Texture::initFromFile(const std::string& newFilename, bool newDynamic, bool newMipmaps)
        {
            free();

            filename = newFilename;

            Image image;
            if (!image.initFromFile(filename))
            {
                return false;
            }

            return initFromBuffer(image.getData(), image.getSize(), dynamic, mipmaps);
        }

        bool Texture::initFromBuffer(const std::vector<uint8_t>& newData, const Size2& newSize, bool newDynamic, bool newMipmaps)
        {
            free();

            dynamic = newDynamic;
            mipmaps = newMipmaps;
            renderTarget = false;

            dirty = true;

            if (!calculateData(newData, newSize))
            {
                return false;
            }

            sharedEngine->getRenderer()->scheduleUpdate(shared_from_this());

            return true;
        }

        static void imageRgba8Downsample2x2(uint32_t width, uint32_t height, uint32_t pitch, const uint8_t* src, uint8_t* dst)
        {
            const uint32_t dstwidth  = width / 2;
            const uint32_t dstheight = height / 2;

            if (dstwidth == 0 ||  dstheight == 0)
            {
                return;
            }

            for (uint32_t y = 0, ystep = pitch * 2; y < dstheight; ++y, src += ystep)
            {
                const uint8_t* rgba = src;
                for (uint32_t x = 0; x < dstwidth; ++x, rgba += 8, dst += 4)
                {
                    float pixels = 0.0f;

                    float r = 0, g = 0, b = 0, a = 0;

                    if (rgba[3] > 0)
                    {
                        r += powf(rgba[0], 2.2f);
                        g += powf(rgba[1], 2.2f);
                        b += powf(rgba[2], 2.2f);
                        pixels += 1.0f;
                    }
                    a = rgba[3];

                    if (rgba[7] > 0)
                    {
                        r += powf(rgba[4], 2.2f);
                        g += powf(rgba[5], 2.2f);
                        b += powf(rgba[6], 2.2f);
                        pixels += 1.0f;
                    }
                    a += rgba[7];

                    if (rgba[pitch+3])
                    {
                        r += powf(rgba[pitch+0], 2.2f);
                        g += powf(rgba[pitch+1], 2.2f);
                        b += powf(rgba[pitch+2], 2.2f);
                        pixels += 1.0f;
                    }
                    a += rgba[pitch+3];

                    if (rgba[pitch+7] > 0)
                    {
                        r += powf(rgba[pitch+4], 2.2f);
                        g += powf(rgba[pitch+5], 2.2f);
                        b += powf(rgba[pitch+6], 2.2f);
                        pixels += 1.0f;
                    }
                    a += rgba[pitch+7];

                    if (pixels > 0.0f)
                    {
                        r /= pixels;
                        g /= pixels;
                        b /= pixels;
                    }
                    else
                    {
                        r = g = b = 0;
                    }

                    a *= 0.25f;
                    r = powf(r, 1.0f / 2.2f);
                    g = powf(g, 1.0f / 2.2f);
                    b = powf(b, 1.0f / 2.2f);
                    dst[0] = (uint8_t)r;
                    dst[1] = (uint8_t)g;
                    dst[2] = (uint8_t)b;
                    dst[3] = (uint8_t)a;
                }
            }
        }

        bool Texture::setData(const std::vector<uint8_t>& newData, const Size2& newSize)
        {
            if (!dynamic)
            {
                return false;
            }

            if (newSize.width <= 0.0f || newSize.height <= 0.0f)
            {
                return false;
            }

            return calculateData(newData, newSize);
        }

        bool Texture::calculateData(const std::vector<uint8_t>& newData, const Size2& newSize)
        {
            levels.clear();
            size = newSize;

            levels.push_back({ newSize, newData });

            uint32_t newWidth = static_cast<uint32_t>(newSize.width);
            uint32_t newHeight = static_cast<uint32_t>(newSize.height);

#if OUZEL_SUPPORTS_OPENGLES
            if (mipmaps && (sharedEngine->getRenderer()->getDriver() != Renderer::Driver::OPENGL || (isPOT(newWidth) && isPOT(newHeight))))
#else
            if (mipmaps)
#endif
            {
                uint32_t pitch = newWidth * 4;

                uint32_t bufferSize = newWidth * newHeight * 4;

                if (newWidth == 1)
                {
                    bufferSize *= 2;
                }
                if (newHeight == 1)
                {
                    bufferSize *= 2;
                }

                std::vector<uint8_t> mipMapData(bufferSize);
                memcpy(mipMapData.data(), newData.data(), newWidth * newHeight * 4);

                while (newWidth >= 2 && newHeight >= 2)
                {
                    imageRgba8Downsample2x2(newWidth, newHeight, pitch, mipMapData.data(), mipMapData.data());

                    newWidth >>= 1;
                    newHeight >>= 1;

                    Size2 mipMapSize = Size2(static_cast<float>(newWidth), static_cast<float>(newHeight));
                    levels.push_back({ mipMapSize, mipMapData });

                    pitch = newWidth * 4;
                }

                if (newWidth > newHeight)
                {
                    for (; newWidth >= 2;)
                    {
                        memcpy(&mipMapData.data()[newWidth*4], mipMapData.data(), newWidth * 4);

                        imageRgba8Downsample2x2(newWidth, 2, pitch, mipMapData.data(), mipMapData.data());

                        newWidth >>= 1;

                        Size2 mipMapSize = Size2(static_cast<float>(newWidth), static_cast<float>(newHeight));
                        levels.push_back({ mipMapSize, mipMapData });

                        pitch = newWidth * 4;
                    }
                }
                else
                {
                    for (; newHeight >= 2;)
                    {
                        uint32_t* src = reinterpret_cast<uint32_t*>(mipMapData.data());
                        for (int32_t i = static_cast<int32_t>(newHeight) - 1; i >= 0; --i)
                        {
                            src[i * 2] = src[i];
                            src[i * 2 + 1] = src[i];
                        }

                        imageRgba8Downsample2x2(2, newHeight, 8, mipMapData.data(), mipMapData.data());

                        newHeight >>= 1;

                        Size2 mipMapSize = Size2(static_cast<float>(newWidth), static_cast<float>(newHeight));
                        levels.push_back({ mipMapSize, mipMapData });
                    }
                }
            }

            sharedEngine->getRenderer()->scheduleUpdate(shared_from_this());

            return true;
        }

        bool Texture::update()
        {
            uploadData.size = size;
            uploadData.dynamic = dynamic;
            uploadData.mipmaps = mipmaps;
            uploadData.renderTarget = renderTarget;

            if (!levels.empty())
            {
                uploadData.levels = std::move(levels);
            }

            return true;
        }
    } // namespace graphics
} // namespace ouzel
<commit_msg>Correctly initialize texture from file<commit_after>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <cstring>
#include "core/CompileConfig.h"
#include "Texture.h"
#include "core/Engine.h"
#include "Renderer.h"
#include "Image.h"
#include "utils/Utils.h"
#include "math/MathUtils.h"

namespace ouzel
{
    namespace graphics
    {
        Texture::Texture()
        {

        }

        Texture::~Texture()
        {

        }

        void Texture::free()
        {
            levels.clear();
            uploadData.levels.clear();

            ready = false;
        }

        bool Texture::init(const Size2& newSize, bool newDynamic, bool newMipmaps, bool newRenderTarget)
        {
            free();

            size = newSize;
            dynamic = newDynamic;
            mipmaps = newMipmaps;
            renderTarget = newRenderTarget;

            dirty = true;

            sharedEngine->getRenderer()->scheduleUpdate(shared_from_this());

            return true;
        }

        bool Texture::initFromFile(const std::string& newFilename, bool newDynamic, bool newMipmaps)
        {
            free();

            filename = newFilename;

            Image image;
            if (!image.initFromFile(filename))
            {
                return false;
            }

            return initFromBuffer(image.getData(), image.getSize(), newDynamic, newMipmaps);
        }

        bool Texture::initFromBuffer(const std::vector<uint8_t>& newData, const Size2& newSize, bool newDynamic, bool newMipmaps)
        {
            free();

            dynamic = newDynamic;
            mipmaps = newMipmaps;
            renderTarget = false;

            dirty = true;

            if (!calculateData(newData, newSize))
            {
                return false;
            }

            sharedEngine->getRenderer()->scheduleUpdate(shared_from_this());

            return true;
        }

        static void imageRgba8Downsample2x2(uint32_t width, uint32_t height, uint32_t pitch, const uint8_t* src, uint8_t* dst)
        {
            const uint32_t dstwidth  = width / 2;
            const uint32_t dstheight = height / 2;

            if (dstwidth == 0 ||  dstheight == 0)
            {
                return;
            }

            for (uint32_t y = 0, ystep = pitch * 2; y < dstheight; ++y, src += ystep)
            {
                const uint8_t* rgba = src;
                for (uint32_t x = 0; x < dstwidth; ++x, rgba += 8, dst += 4)
                {
                    float pixels = 0.0f;

                    float r = 0, g = 0, b = 0, a = 0;

                    if (rgba[3] > 0)
                    {
                        r += powf(rgba[0], 2.2f);
                        g += powf(rgba[1], 2.2f);
                        b += powf(rgba[2], 2.2f);
                        pixels += 1.0f;
                    }
                    a = rgba[3];

                    if (rgba[7] > 0)
                    {
                        r += powf(rgba[4], 2.2f);
                        g += powf(rgba[5], 2.2f);
                        b += powf(rgba[6], 2.2f);
                        pixels += 1.0f;
                    }
                    a += rgba[7];

                    if (rgba[pitch+3])
                    {
                        r += powf(rgba[pitch+0], 2.2f);
                        g += powf(rgba[pitch+1], 2.2f);
                        b += powf(rgba[pitch+2], 2.2f);
                        pixels += 1.0f;
                    }
                    a += rgba[pitch+3];

                    if (rgba[pitch+7] > 0)
                    {
                        r += powf(rgba[pitch+4], 2.2f);
                        g += powf(rgba[pitch+5], 2.2f);
                        b += powf(rgba[pitch+6], 2.2f);
                        pixels += 1.0f;
                    }
                    a += rgba[pitch+7];

                    if (pixels > 0.0f)
                    {
                        r /= pixels;
                        g /= pixels;
                        b /= pixels;
                    }
                    else
                    {
                        r = g = b = 0;
                    }

                    a *= 0.25f;
                    r = powf(r, 1.0f / 2.2f);
                    g = powf(g, 1.0f / 2.2f);
                    b = powf(b, 1.0f / 2.2f);
                    dst[0] = (uint8_t)r;
                    dst[1] = (uint8_t)g;
                    dst[2] = (uint8_t)b;
                    dst[3] = (uint8_t)a;
                }
            }
        }

        bool Texture::setData(const std::vector<uint8_t>& newData, const Size2& newSize)
        {
            if (!dynamic)
            {
                return false;
            }

            if (newSize.width <= 0.0f || newSize.height <= 0.0f)
            {
                return false;
            }

            return calculateData(newData, newSize);
        }

        bool Texture::calculateData(const std::vector<uint8_t>& newData, const Size2& newSize)
        {
            levels.clear();
            size = newSize;

            levels.push_back({ newSize, newData });

            uint32_t newWidth = static_cast<uint32_t>(newSize.width);
            uint32_t newHeight = static_cast<uint32_t>(newSize.height);

#if OUZEL_SUPPORTS_OPENGLES
            if (mipmaps && (sharedEngine->getRenderer()->getDriver() != Renderer::Driver::OPENGL || (isPOT(newWidth) && isPOT(newHeight))))
#else
            if (mipmaps)
#endif
            {
                uint32_t pitch = newWidth * 4;

                uint32_t bufferSize = newWidth * newHeight * 4;

                if (newWidth == 1)
                {
                    bufferSize *= 2;
                }
                if (newHeight == 1)
                {
                    bufferSize *= 2;
                }

                std::vector<uint8_t> mipMapData(bufferSize);
                memcpy(mipMapData.data(), newData.data(), newWidth * newHeight * 4);

                while (newWidth >= 2 && newHeight >= 2)
                {
                    imageRgba8Downsample2x2(newWidth, newHeight, pitch, mipMapData.data(), mipMapData.data());

                    newWidth >>= 1;
                    newHeight >>= 1;

                    Size2 mipMapSize = Size2(static_cast<float>(newWidth), static_cast<float>(newHeight));
                    levels.push_back({ mipMapSize, mipMapData });

                    pitch = newWidth * 4;
                }

                if (newWidth > newHeight)
                {
                    for (; newWidth >= 2;)
                    {
                        memcpy(&mipMapData.data()[newWidth*4], mipMapData.data(), newWidth * 4);

                        imageRgba8Downsample2x2(newWidth, 2, pitch, mipMapData.data(), mipMapData.data());

                        newWidth >>= 1;

                        Size2 mipMapSize = Size2(static_cast<float>(newWidth), static_cast<float>(newHeight));
                        levels.push_back({ mipMapSize, mipMapData });

                        pitch = newWidth * 4;
                    }
                }
                else
                {
                    for (; newHeight >= 2;)
                    {
                        uint32_t* src = reinterpret_cast<uint32_t*>(mipMapData.data());
                        for (int32_t i = static_cast<int32_t>(newHeight) - 1; i >= 0; --i)
                        {
                            src[i * 2] = src[i];
                            src[i * 2 + 1] = src[i];
                        }

                        imageRgba8Downsample2x2(2, newHeight, 8, mipMapData.data(), mipMapData.data());

                        newHeight >>= 1;

                        Size2 mipMapSize = Size2(static_cast<float>(newWidth), static_cast<float>(newHeight));
                        levels.push_back({ mipMapSize, mipMapData });
                    }
                }
            }

            sharedEngine->getRenderer()->scheduleUpdate(shared_from_this());

            return true;
        }

        bool Texture::update()
        {
            uploadData.size = size;
            uploadData.dynamic = dynamic;
            uploadData.mipmaps = mipmaps;
            uploadData.renderTarget = renderTarget;

            if (!levels.empty())
            {
                uploadData.levels = std::move(levels);
            }

            return true;
        }
    } // namespace graphics
} // namespace ouzel
<|endoftext|>


<commit_before>/**
 * Created by Jian Chen
 * @since  2017.02.03
 * @author Jian Chen <admin@chensoft.com>
 * @link   http://chensoft.com
 */
#pragma once

#include <socket/base/ev_base.hpp>
#include <functional>
#include <chrono>

namespace chen
{
    class ev_timer: public ev_base
    {
    public:
        ev_timer(std::function<void ()> cb = nullptr);

    public:
        /**
         * Invoke callback only once after a period of time
         */
        void timeout(const std::chrono::nanoseconds &value);

        /**
         * Invoke callback only once in a future calendar date
         */
        void future(const std::chrono::high_resolution_clock::time_point &value);

        /**
         * Invoke callback repeatedly after a period of time
         */
        void interval(const std::chrono::nanoseconds &value);

    public:
        /**
         * Attach callback
         */
        void attach(std::function<void ()> cb);

    public:
        /**
         * Timer properties
         */
        bool repeat() const
        {
            return this->_repeat;
        }

        std::chrono::nanoseconds cycle() const
        {
            return this->_cycle;
        }

        std::chrono::high_resolution_clock::time_point alarm() const
        {
            return this->_alarm;
        }

        /**
         * Calculate init value
         */
        void setup(const std::chrono::high_resolution_clock::time_point &now);

        /**
         * Check if timer expire
         */
        bool expire(const std::chrono::high_resolution_clock::time_point &now) const;

        /**
         * Update timer value
         */
        void update(const std::chrono::high_resolution_clock::time_point &now);

        /**
         * Comparator, used in conjunction with multiset
         * @note if alarm value is changed, you should re-add timer to multiset
         */
        struct Compare
        {
            bool operator()(const ev_timer *a, const ev_timer *b) const
            {
                return a->alarm() < b->alarm();
            }
        };

    protected:
        /**
         * At least one event has occurred
         */
        virtual void onEvent(int type);

    private:
        bool _repeat = false;
        std::function<void ()> _notify;

        std::chrono::nanoseconds _cycle;  // value when call timeout or interval
        std::chrono::high_resolution_clock::time_point _alarm;  // the next trigger time point
    };
}<commit_msg>timer: if alarm is equal then check cycle, let the minimum first trigger<commit_after>/**
 * Created by Jian Chen
 * @since  2017.02.03
 * @author Jian Chen <admin@chensoft.com>
 * @link   http://chensoft.com
 */
#pragma once

#include <socket/base/ev_base.hpp>
#include <functional>
#include <chrono>

namespace chen
{
    class ev_timer: public ev_base
    {
    public:
        ev_timer(std::function<void ()> cb = nullptr);

    public:
        /**
         * Invoke callback only once after a period of time
         */
        void timeout(const std::chrono::nanoseconds &value);

        /**
         * Invoke callback only once in a future calendar date
         */
        void future(const std::chrono::high_resolution_clock::time_point &value);

        /**
         * Invoke callback repeatedly after a period of time
         */
        void interval(const std::chrono::nanoseconds &value);

    public:
        /**
         * Attach callback
         */
        void attach(std::function<void ()> cb);

    public:
        /**
         * Timer properties
         */
        bool repeat() const
        {
            return this->_repeat;
        }

        std::chrono::nanoseconds cycle() const
        {
            return this->_cycle;
        }

        std::chrono::high_resolution_clock::time_point alarm() const
        {
            return this->_alarm;
        }

        /**
         * Calculate init value
         */
        void setup(const std::chrono::high_resolution_clock::time_point &now);

        /**
         * Check if timer expire
         */
        bool expire(const std::chrono::high_resolution_clock::time_point &now) const;

        /**
         * Update timer value
         */
        void update(const std::chrono::high_resolution_clock::time_point &now);

        /**
         * Comparator, used in conjunction with multiset
         * @note if the cycle or alarm value changes, you should re-add the timer to multiset
         */
        struct Compare
        {
            bool operator()(const ev_timer *a, const ev_timer *b) const
            {
                auto alarm_a = a->alarm();
                auto alarm_b = b->alarm();
                return alarm_a == alarm_b ? a->cycle() < b->cycle() : alarm_a < alarm_b;
            }
        };

    protected:
        /**
         * At least one event has occurred
         */
        virtual void onEvent(int type);

    private:
        bool _repeat = false;
        std::function<void ()> _notify;

        std::chrono::nanoseconds _cycle;  // value when call timeout or interval
        std::chrono::high_resolution_clock::time_point _alarm;  // the next trigger time point
    };
}<|endoftext|>


<commit_before>// Copyright (c) 2014-2017 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAOCPP_PEGTL_INCLUDE_READ_INPUT_HPP
#define TAOCPP_PEGTL_INCLUDE_READ_INPUT_HPP

#include <string>

#include "config.hpp"
#include "eol.hpp"
#include "string_input.hpp"
#include "tracking_mode.hpp"

#include "internal/file_reader.hpp"

namespace tao
{
   namespace TAOCPP_PEGTL_NAMESPACE
   {
      namespace internal
      {
         struct filename_holder
         {
            const std::string data;

            template< typename T >
            explicit filename_holder( T&& in_data )
               : data( std::forward< T >( in_data ) )
            {
            }
         };

      }  // namespace internal

      template< typename Eol = lf_crlf_eol, tracking_mode P = tracking_mode::IMMEDIATE >
      struct read_input
         : private internal::filename_holder,
           public string_input< Eol, P >
      {
         template< typename T >
         explicit read_input( T&& filename )
            : internal::filename_holder( std::forward< T >( filename ) ),
              string_input< Eol, P >( internal::file_reader( data.c_str() ).read(), data.c_str() )
         {
         }
      };

   }  // namespace TAOCPP_PEGTL_NAMESPACE

}  // namespace tao

#endif
<commit_msg>Work-around for MSVC<commit_after>// Copyright (c) 2014-2017 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAOCPP_PEGTL_INCLUDE_READ_INPUT_HPP
#define TAOCPP_PEGTL_INCLUDE_READ_INPUT_HPP

#include <string>

#include "config.hpp"
#include "eol.hpp"
#include "string_input.hpp"
#include "tracking_mode.hpp"

#include "internal/file_reader.hpp"

namespace tao
{
   namespace TAOCPP_PEGTL_NAMESPACE
   {
      namespace internal
      {
         struct filename_holder
         {
            const std::string filename;

            template< typename T >
            explicit filename_holder( T&& in_filename )
               : filename( std::forward< T >( in_filename ) )
            {
            }
         };

      }  // namespace internal

      template< typename Eol = lf_crlf_eol, tracking_mode P = tracking_mode::IMMEDIATE >
      struct read_input
         : private internal::filename_holder,
           public string_input< Eol, P >
      {
         template< typename T, typename... Ts >
         explicit read_input( T&& in_filename, Ts&&... ts )
            : internal::filename_holder( std::forward< T >( in_filename ) ),
              string_input< Eol, P >( internal::file_reader( filename.c_str() ).read(), filename.c_str(), std::forward< Ts >( ts )... )
         {
         }
      };

   }  // namespace TAOCPP_PEGTL_NAMESPACE

}  // namespace tao

#endif
<|endoftext|>