<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Hidekazu Ikeno
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

///
/// \file approx_sph_bessel.hpp
/// Exponential sum approximations of the spherical Bessel functions.
///

#ifndef MXPFIT_APPROX_SPH_BESSEL_HPP
#define MXPFIT_APPROX_SPH_BESSEL_HPP

#include <iosfwd>

#include <mxpfit/math/legendre.hpp>

#include <mxpfit/quad/tanh_sinh_rule.hpp>

#include <mxpfit/balanced_truncation.hpp>
#include <mxpfit/exponential_sum.hpp>

namespace mxpfit
{
///
/// ### ApproxSphBesselFunction
///
/// Compute the multi-exponential function that approximates the spherical
/// Bessel function of the first kind such that
///
/// \f[
///   \|j_{n}(x)-sum_{m=1}^{M} w_{m} e^{-a_{m} x} \| < \epsilon
/// \f]
///
/// for integer `n` on real axis `(x)`, where \f$ \epsilon \f$ is an arbitrary
/// small positive number.
///
/// The multi-exponential function is obtained by discretize the integral
/// representation of spherical Bessel function
///
/// \f[
///   j_{n}(x)=\int_{-1}^{1} e^{ixt} P_n(t) dt
/// \f]
///
/// The integrand in above expression is highly oscillating when `x` becomes
/// large, thus the direct application of some quadrature rule is inefficient.
/// To avoid this problem, we extend the integral on the complex plane and
/// select the contour as the steepest descent paths, as follows.
///
/// \f{eqnarray*}{
///   j_{n}(x) &=& I_1 + I_2 + (-1)^{n}(I_1^{\ast} + I_{2}^{\ast}), \\
///   I_{1} &=& \frac{(-i)^{n+1}}{2} \int_{0}^{R} e^{-(y-i)x} P_{n}(1+iy) dy, \\
///   I_{2} &=& \frac{(-i)^{n}}{2} \int_{-1}^{0} e^{-(R-ix)y} P_{n}(y+iR) dy, \\
/// \f}
///
/// The integrals \f$ I_1 \f$ and \f$ I_2 \f$ are discretized using appropriate
/// quadrature rule, then the balanced truncation method is applied to reduce
/// the number of terms.
///
template <typename T>
class ApproxSphBesselFunction
{
public:
    using Index      = Eigen::Index;
    using Real       = T;
    using Complex    = std::complex<Real>;
    using ResultType = ExponentialSum<Complex, Complex>;

    ApproxSphBesselFunction()                               = default;
    ApproxSphBesselFunction(const ApproxSphBesselFunction&) = default;
    ApproxSphBesselFunction(ApproxSphBesselFunction&&)      = default;

    ///
    /// Create an instance with arguments.
    ///
    /// \param[in] n the order of the spherical Bessel function, \f$j_n(z)\f$
    /// \param[in] threshold the target accuracy of the exponential sum
    ///                      approximation
    /// \pre `n >= 0 && eps > 0`
    ///
    ApproxSphBesselFunction(Index n, Real threshold)
        : m_order(n), m_threshold(threshold)
    {
        assert(n >= Index() &&
               "invalid value for the argument `n`: n >= 0 is required");
        assert(threshold > Real() &&
               "invalid value for the argument `threshold`: "
               "threshold > 0.0 is required");
    }

    ~ApproxSphBesselFunction() = default;

    ApproxSphBesselFunction&
    operator=(const ApproxSphBesselFunction&) = default;
    ApproxSphBesselFunction& operator=(ApproxSphBesselFunction&&) = default;

    /// Get the order of spherical Bessel function
    Index order() const
    {
        return m_order;
    }

    /// Get the prescribed accuracy of the exponential sum approximation
    Real threshold() const
    {
        return m_threshold;
    }

    ///
    /// Set parameters
    ///
    void set_params(Index n, Real threshold)
    {
        assert(n >= Index() &&
               "invalid value for the argument `n`: n >= 0 is required");
        assert(threshold > Real() &&
               "invalid value for the argument `threshold`: "
               "threshold > 0.0 is required");
        m_order     = n;
        m_threshold = threshold;
    }

    ///
    /// Compute the exponential sum approximation with the parameters set in
    /// advance via constructor or `set_params` method.
    ///
    ResultType compute() const;

    ///
    /// Compute the exponential sum approximation with the given parameters.
    ///
    ResultType compute(Index n, Real threshold)
    {
        set_params(n, threshold);
        return compute();
    }

    ///
    /// Print parameters to the given ostream
    ///
    template <typename Ch, typename Tr>
    void print(std::basic_ostream<Ch, Tr>& os) const;

private:
    Index m_order;
    Real m_threshold;
};

// ostream operator
template <typename Ch, typename Tr, typename T>
std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& os,
                                       const ApproxSphBesselFunction<T>& es)
{
    es.print(os);
    return os;
}

//
// --- Implementations of member functions
//
template <typename T>
typename ApproxSphBesselFunction<T>::ResultType
ApproxSphBesselFunction<T>::compute() const
{
    using Eigen::numext::conj;
    using Eigen::numext::log;
    using Eigen::numext::cos;
    using Eigen::numext::sin;
    using Eigen::numext::exp;

    // ----- Constants
    constexpr const auto zero = Real();
    constexpr const auto one  = Real(1);
    constexpr const auto half = Real(0.5);
    constexpr const auto eps  = std::numeric_limits<Real>::epsilon();
    // (-i)^n
    constexpr const Complex pow_i[4] = {Complex(one, zero), Complex(zero, -one),
                                        Complex(-one, zero),
                                        Complex(zero, one)};

    const Index n = m_order;

    //----- adjustable parameters
    const auto R       = Real(4) / std::max(Index(1), n);
    const auto n_quad1 = Index(200);
    const auto tiny1   = eps / n_quad1;

    const auto n_quad2 = Index(120 + 2 * n);
    const auto tiny2   = eps / n_quad2;
    //---------------------------

    //
    // Find R_shift such that j_n(R_shift) < eps
    //
    Real R_shift = Real();
    if (n > Index())
    {
        Real log_dfact = Real(); // log[(2n+1)!!]
        for (Index k = 1; k <= n; ++k)
        {
            log_dfact += log(Real(2 * k + 1));
        }
        const auto thresh = std::min(m_threshold, sqrt(eps));
        R_shift           = exp((log_dfact + log(thresh)) / Real(n));
        if (R_shift < Real(0.1))
        {
            R_shift = Real();
        }
        // std::cout << "*** l = " << n << ", R_shift = " << R_shift << '\n';
    }

    //
    // Discretization of integral I_1 on the path `-1 + i y`  for
    // `0 <= y <= R`
    //
    quad::DESinhTanhRule<T> rule1(n_quad1, tiny1);
    ResultType es1(n_quad1);

    const auto R_half = R / 2;

    for (Index k = 0; k < n_quad1; ++k)
    {
        const auto yk = R_half * rule1.distanceFromLower(k); // node
        const auto wk = R_half * rule1.w(k);                 // weight
        const auto ak = Complex(yk, one);
        const auto pk = Complex(zero, wk) * exp(ak * R_shift) *
                        math::legendre_p(n, Complex(-one, yk));

        es1.exponent(k) = ak;
        es1.weight(k)   = pk;
    }

    //
    // Discretization of integral I_2 on the path `x + iR` for
    // `0 <= x <= 1`
    //
    quad::DESinhTanhRule<T> rule2(n_quad2, tiny2);
    ResultType es2(n_quad2);

    for (Index k = 0; k < n_quad2; ++k)
    {
        const auto xk = half * rule2.distanceFromLower(k); // node
        const auto wk = half * rule2.w(k);                 // weight
        const auto ak = Complex(R, -xk);
        const auto pk =
            wk * exp(ak * R_shift) * math::legendre_p(n, Complex(xk, R));

        es2.exponent(k) = ak;
        es2.weight(k)   = pk;
    }

    //
    // Truncation for I_1 and I_2 separately
    //
    // mxpfit::BalancedTruncation<Complex> trunc1;
    // trunc1.setThreshold(threshold);
    // es1 = trunc1.compute(es1);

    // mxpfit::BalancedTruncation<Complex> trunc2;
    // trunc2.setThreshold(threshold);
    // es2 = trunc2.compute(es2);

    //
    // Merge two sums
    //
    ResultType es_merged(es1.size() + es2.size());
    es_merged.exponents().head(es1.size()) = es1.exponents();
    es_merged.exponents().tail(es2.size()) = es2.exponents();
    es_merged.weights().head(es1.size())   = es1.weights();
    es_merged.weights().tail(es2.size())   = es2.weights();

    //
    // Truncation for I_1 and I_2 simultaneously
    //
    mxpfit::BalancedTruncation<Complex> trunc1;
    es_merged = trunc1.compute(es_merged, m_threshold);

    ResultType es_result(2 * es_merged.size());

    const auto pre1 = pow_i[n % 4] / Real(2); // (-i)^n / 2
    const auto pre2 = (n & 1) ? -pre1 : pre1;

    for (Index i = 0; i < es_merged.size(); ++i)
    {
        const auto ai                 = es_merged.exponent(i);
        es_result.exponent(2 * i + 0) = ai;
        es_result.exponent(2 * i + 1) = conj(ai);

        const auto wi               = es_merged.weight(i) * exp(-ai * R_shift);
        es_result.weight(2 * i + 0) = pre1 * wi;
        es_result.weight(2 * i + 1) = pre2 * conj(wi);
    }

    return es_result;
}

///
/// Compute exponential sum approximations of spherical Bessel functions
///
template <typename T>
ExponentialSum<std::complex<T>> approx_sph_bessel(Eigen::Index n, T threshold)
{
    ApproxSphBesselFunction<T> approx(n, threshold);
    return approx.compute();
}

} // namespace mxpfit
#endif /* MXPFIT_APPROX_SPH_BESSEL_HPP */
<commit_msg>Modify doxygen comment<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Hidekazu Ikeno
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

///
/// \file approx_sph_bessel.hpp
/// \brief Find exponential sum approximations of the spherical Bessel
/// functions.
///

#ifndef MXPFIT_APPROX_SPH_BESSEL_HPP
#define MXPFIT_APPROX_SPH_BESSEL_HPP

#include <iosfwd>

#include <mxpfit/math/legendre.hpp>

#include <mxpfit/quad/tanh_sinh_rule.hpp>

#include <mxpfit/balanced_truncation.hpp>
#include <mxpfit/exponential_sum.hpp>

namespace mxpfit
{
///
/// ### ApproxSphBesselFunction
///
/// Compute the multi-exponential function that approximates the spherical
/// Bessel function of the first kind such that
///
/// \f[
///   \|j_{n}(x)-sum_{m=1}^{M} w_{m} e^{-a_{m} x} \| < \epsilon
/// \f]
///
/// for integer `n` on real axis `(x)`, where \f$ \epsilon \f$ is an arbitrary
/// small positive number.
///
/// The multi-exponential function is obtained by discretize the integral
/// representation of spherical Bessel function
///
/// \f[
///   j_{n}(x)=\int_{-1}^{1} e^{ixt} P_n(t) dt
/// \f]
///
/// The integrand in above expression is highly oscillating when `x` becomes
/// large, thus the direct application of some quadrature rule is inefficient.
/// To avoid this problem, we extend the integral on the complex plane and
/// select the contour as the steepest descent paths, as follows.
///
/// \f{eqnarray*}{
///   j_{n}(x) &=& I_1 + I_2 + (-1)^{n}(I_1^{\ast} + I_{2}^{\ast}), \\
///   I_{1} &=& \frac{(-i)^{n+1}}{2} \int_{0}^{R} e^{-(y-i)x} P_{n}(1+iy) dy, \\
///   I_{2} &=& \frac{(-i)^{n}}{2} \int_{-1}^{0} e^{-(R-ix)y} P_{n}(y+iR) dy, \\
/// \f}
///
/// The integrals \f$ I_1 \f$ and \f$ I_2 \f$ are discretized using appropriate
/// quadrature rule, then the balanced truncation method is applied to reduce
/// the number of terms.
///
template <typename T>
class ApproxSphBesselFunction
{
public:
    using Index      = Eigen::Index;
    using Real       = T;
    using Complex    = std::complex<Real>;
    using ResultType = ExponentialSum<Complex, Complex>;

    ApproxSphBesselFunction()                               = default;
    ApproxSphBesselFunction(const ApproxSphBesselFunction&) = default;
    ApproxSphBesselFunction(ApproxSphBesselFunction&&)      = default;

    ///
    /// Create an instance with arguments.
    ///
    /// \param[in] n the order of the spherical Bessel function, \f$j_n(z)\f$
    /// \param[in] threshold the target accuracy of the exponential sum
    ///                      approximation
    /// \pre `n >= 0 && eps > 0`
    ///
    ApproxSphBesselFunction(Index n, Real threshold)
        : m_order(n), m_threshold(threshold)
    {
        assert(n >= Index() &&
               "invalid value for the argument `n`: n >= 0 is required");
        assert(threshold > Real() &&
               "invalid value for the argument `threshold`: "
               "threshold > 0.0 is required");
    }

    ~ApproxSphBesselFunction() = default;

    ApproxSphBesselFunction&
    operator=(const ApproxSphBesselFunction&) = default;
    ApproxSphBesselFunction& operator=(ApproxSphBesselFunction&&) = default;

    /// Get the order of spherical Bessel function
    Index order() const
    {
        return m_order;
    }

    /// Get the prescribed accuracy of the exponential sum approximation
    Real threshold() const
    {
        return m_threshold;
    }

    ///
    /// Set parameters
    ///
    void set_params(Index n, Real threshold)
    {
        assert(n >= Index() &&
               "invalid value for the argument `n`: n >= 0 is required");
        assert(threshold > Real() &&
               "invalid value for the argument `threshold`: "
               "threshold > 0.0 is required");
        m_order     = n;
        m_threshold = threshold;
    }

    ///
    /// Compute the exponential sum approximation with the parameters set in
    /// advance via constructor or `set_params` method.
    ///
    ResultType compute() const;

    ///
    /// Compute the exponential sum approximation with the given parameters.
    ///
    ResultType compute(Index n, Real threshold)
    {
        set_params(n, threshold);
        return compute();
    }

    ///
    /// Print parameters to the given ostream
    ///
    template <typename Ch, typename Tr>
    void print(std::basic_ostream<Ch, Tr>& os) const;

private:
    Index m_order;
    Real m_threshold;
};

// ostream operator
template <typename Ch, typename Tr, typename T>
std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& os,
                                       const ApproxSphBesselFunction<T>& es)
{
    es.print(os);
    return os;
}

//
// --- Implementations of member functions
//
template <typename T>
typename ApproxSphBesselFunction<T>::ResultType
ApproxSphBesselFunction<T>::compute() const
{
    using Eigen::numext::conj;
    using Eigen::numext::cos;
    using Eigen::numext::exp;
    using Eigen::numext::log;
    using Eigen::numext::sin;

    // ----- Constants
    constexpr const auto zero = Real();
    constexpr const auto one  = Real(1);
    constexpr const auto half = Real(0.5);
    constexpr const auto eps  = std::numeric_limits<Real>::epsilon();
    // (-i)^n
    constexpr const Complex pow_i[4] = {Complex(one, zero), Complex(zero, -one),
                                        Complex(-one, zero),
                                        Complex(zero, one)};

    const Index n = m_order;

    //----- adjustable parameters
    const auto R       = Real(4) / std::max(Index(1), n);
    const auto n_quad1 = Index(200);
    const auto tiny1   = eps / n_quad1;

    const auto n_quad2 = Index(120 + 2 * n);
    const auto tiny2   = eps / n_quad2;
    //---------------------------

    //
    // Find R_shift such that j_n(R_shift) < eps
    //
    Real R_shift = Real();
    if (n > Index())
    {
        Real log_dfact = Real(); // log[(2n+1)!!]
        for (Index k = 1; k <= n; ++k)
        {
            log_dfact += log(Real(2 * k + 1));
        }
        const auto thresh = std::min(m_threshold, sqrt(eps));
        R_shift           = exp((log_dfact + log(thresh)) / Real(n));
        if (R_shift < Real(0.1))
        {
            R_shift = Real();
        }
        // std::cout << "*** l = " << n << ", R_shift = " << R_shift << '\n';
    }

    //
    // Discretization of integral I_1 on the path `-1 + i y`  for
    // `0 <= y <= R`
    //
    quad::DESinhTanhRule<T> rule1(n_quad1, tiny1);
    ResultType es1(n_quad1);

    const auto R_half = R / 2;

    for (Index k = 0; k < n_quad1; ++k)
    {
        const auto yk = R_half * rule1.distanceFromLower(k); // node
        const auto wk = R_half * rule1.w(k);                 // weight
        const auto ak = Complex(yk, one);
        const auto pk = Complex(zero, wk) * exp(ak * R_shift) *
                        math::legendre_p(n, Complex(-one, yk));

        es1.exponent(k) = ak;
        es1.weight(k)   = pk;
    }

    //
    // Discretization of integral I_2 on the path `x + iR` for
    // `0 <= x <= 1`
    //
    quad::DESinhTanhRule<T> rule2(n_quad2, tiny2);
    ResultType es2(n_quad2);

    for (Index k = 0; k < n_quad2; ++k)
    {
        const auto xk = half * rule2.distanceFromLower(k); // node
        const auto wk = half * rule2.w(k);                 // weight
        const auto ak = Complex(R, -xk);
        const auto pk =
            wk * exp(ak * R_shift) * math::legendre_p(n, Complex(xk, R));

        es2.exponent(k) = ak;
        es2.weight(k)   = pk;
    }

    //
    // Truncation for I_1 and I_2 separately
    //
    // mxpfit::BalancedTruncation<Complex> trunc1;
    // trunc1.setThreshold(threshold);
    // es1 = trunc1.compute(es1);

    // mxpfit::BalancedTruncation<Complex> trunc2;
    // trunc2.setThreshold(threshold);
    // es2 = trunc2.compute(es2);

    //
    // Merge two sums
    //
    ResultType es_merged(es1.size() + es2.size());
    es_merged.exponents().head(es1.size()) = es1.exponents();
    es_merged.exponents().tail(es2.size()) = es2.exponents();
    es_merged.weights().head(es1.size())   = es1.weights();
    es_merged.weights().tail(es2.size())   = es2.weights();

    //
    // Truncation for I_1 and I_2 simultaneously
    //
    mxpfit::BalancedTruncation<Complex> trunc1;
    es_merged = trunc1.compute(es_merged, m_threshold);

    ResultType es_result(2 * es_merged.size());

    const auto pre1 = pow_i[n % 4] / Real(2); // (-i)^n / 2
    const auto pre2 = (n & 1) ? -pre1 : pre1;

    for (Index i = 0; i < es_merged.size(); ++i)
    {
        const auto ai                 = es_merged.exponent(i);
        es_result.exponent(2 * i + 0) = ai;
        es_result.exponent(2 * i + 1) = conj(ai);

        const auto wi               = es_merged.weight(i) * exp(-ai * R_shift);
        es_result.weight(2 * i + 0) = pre1 * wi;
        es_result.weight(2 * i + 1) = pre2 * conj(wi);
    }

    return es_result;
}

///
/// Compute exponential sum approximations of spherical Bessel functions
///
template <typename T>
ExponentialSum<std::complex<T>> approx_sph_bessel(Eigen::Index n, T threshold)
{
    ApproxSphBesselFunction<T> approx(n, threshold);
    return approx.compute();
}

} // namespace mxpfit
#endif /* MXPFIT_APPROX_SPH_BESSEL_HPP */
<|endoftext|>


<commit_before>#pragma once

#include <algorithm>
#include <map>
#include <vector>

#include "nifty/marray/marray.hxx"
#include "nifty/parallel/threadpool.hxx"

namespace nifty {
namespace tools {

template<class EDGE_TYPE, class NODE_TYPE>
class EdgeMapping {

public:

    typedef EDGE_TYPE EdgeType;
    typedef NODE_TYPE NodeType;
    typedef std::pair<NodeType, NodeType> UvType;
    typedef std::vector<UvType> UvVectorType;

    EdgeMapping(const size_t numberOfEdges, const int nThreads=-1)
        : oldToNewEdges_(numberOfEdges), newUvIds_(), threadpool_(nThreads)
    {}

    void initializeMapping(const marray::View<EdgeType> & uvIds, const std::vector<NodeType> & oldToNewNodes);

    template<class T>
    void mapEdgeValues(const std::vector<T> & edgeValues, std::vector<T> & newEdgeValues) const;

    const UvVectorType & getNewUvIds() const
    {return newUvIds_;}

    void getNewEdgeIds(const std::vector<EdgeType> & edgeIds, std::vector<EdgeType> & newEdgeIds) const;

    size_t numberOfNewEdges() const
    {return newUvIds_.size();}

private:

    //std::map<EdgeType, std::vector<EdgeType>> newToOldEdges_;
    std::vector<EdgeType> oldToNewEdges_;
    UvVectorType newUvIds_;
    mutable parallel::ThreadPool threadpool_;
};

// TODO parallelize ?!
template<class EDGE_TYPE, class NODE_TYPE>
void EdgeMapping<EDGE_TYPE, NODE_TYPE>::initializeMapping(const marray::View<EdgeType> & uvIds, const std::vector<NodeType> & oldToNewNodes)
{
    //NodeType uNew, vNew;
    //UvType uvNew;
    //std::map<UvType, EdgeType> indexMap;
    //EdgeType index = 0;

    //for(EdgeType i = 0; i < uvIds.shape(0); ++i) {
    //    uNew = oldToNewNodes[uvIds(i,0)];
    //    vNew = oldToNewNodes[uvIds(i,1)];

    //    if(uNew == vNew) {
    //        oldToNewEdges_[i] = -1;
    //        continue;
    //    }

    //    uvNew = std::make_pair(std::min(uNew, vNew), std::max(uNew, vNew));

    //    auto e = indexMap.insert(std::make_pair(uvNew, index));
    //    if(e.second) {
    //        newUvIds_.push_back(uvNew);
    //        ++index;
    //    }

    //    oldToNewEdges_[i] = e.first->second;
    //}

    std::vector< std::map<UvType, std::vector<EdgeType>> > threadMaps(threadpool_.nThreads());

    // find new uv ids in parallel
    parallel::parallel_foreach(threadpool_, uvIds.shape(0), [&](const int tId, const EdgeType edgeId){
        NodeType uNew, vNew = oldToNewNodes[uvIds(edgeId, 0)], oldToNewNodes[uvIds(edgeId, 1)];

        if(uNew == vNew) {
            //NOTE this is threadsafe, because we are looping over edgeId in parralel
            oldToNewEdges_[edgeId] = -1;
            return;
        }

        // perform map insertion with hint
        auto & thisMap = threadMaps[tId];
        auto uvNew = std::make_pair(std::min(uNew, vNew), std::max(uNew, vNew));
        auto mapIt = thisMap.lower_bound(uvNew);
        // key is already in map
        if( mapIt != thisMap.end() && !(thisMap.key_comp()(uvNew, mapIt->first)) ) {
            mapIt->second.push_back(edgeId);
        }
        else { // key is not in map
            //thisMap.insert(mapIt, std::make_pair(uvNew, std::vector<EdgeType>({edgeId})) );
            thisMap.emplace_hint(mapIt, uvNew, std::vector<EdgeType>({edgeId}));
        }

    });

    // find the unique new uv-ids with a set, then copy them in a vector to have
    // constant time access
    std::set<UvType> uniqueKeysTmp;
    for(size_t t = 0; t < threadpool_.nThreads(); ++t) {
        const auto & thisMap = threadMaps[t];
        for(auto mapIt = thisMap.begin(); mapIt != thisMap.end(); ++mapIt) {
            uniqueKeysTmp.insert(mapIt->first);
        }
    }
    std::vector<UvType> uniqueKeys(uniqueKeysTmp.size());
    std::copy(uniqueKeysTmp.begin(), uniqueKeysTmp.end(), uniqueKeys.begin());

    // find old to new edges in parallel by going over the unique new uv-ids
    parallel::parallel_foreach(threadpool_, uniqueKeys.size(), [&](const int tId, const int newEdgeId){

        // acces the uv id in the set by index
        //
        const auto & uvNew = uniqueKeys[newEdgeId];

        for(int t = 0; t < threadpool_.nThreads(); ++t) {
            const auto & thisMap = threadMaps[t];
            auto mapIt = thisMap.find(uvNew);
            if(mapIt != thisMap.end()) {
                for(auto oldEdgeId : mapIt->second) {
                    oldToNewEdges_[oldEdgeId] = newEdgeId;
                }
            }
        }
    });

}

template<class EDGE_TYPE, class NODE_TYPE>
template<class T>
void EdgeMapping<EDGE_TYPE, NODE_TYPE>::mapEdgeValues(
        const std::vector<T> & edgeValues, std::vector<T> & newEdgeValues) const {

    NIFTY_CHECK_OP(edgeValues.size(),==,oldToNewEdges_.size(),"Wrong Input size");

    newEdgeValues.clear();
    newEdgeValues.resize(newUvIds_.size(), 0);

    // initialise the thread data
    std::vector<std::vector<T>> threadVecs(threadpool_.nThreads());
    parallel::parallel_foreach(threadpool_, threadpool_.nThreads(), [&](const int t, const int i){
        threadVecs[i] = std::vector<T>(newUvIds_.size(), 0);
    });

    // extract the new edge values in parallel over the old edges
    parallel::parallel_foreach(threadpool_, edgeValues.size(), [&](const int tId, const int edgeId){
        auto newEdge = oldToNewEdges_[edgeId];
        if(newEdge != -1) {
            auto & newVals = threadVecs[tId];
            newVals[newEdge] += edgeValues[edgeId];
        }
    });

    // write to the out vector in parallel over the new edges
    parallel::parallel_foreach(threadpool_, newEdgeValues.size(), [&](const int tId, const int newEdgeId){
        auto & destValue = newEdgeValues[newEdgeId];
        for(int t = 0; t < threadpool_.nThreads(); ++t) {
            auto & srcValues = threadVecs[t];
            destValue += srcValues[newEdgeId];
        }
    });

}

template<class EDGE_TYPE, class NODE_TYPE>
void EdgeMapping<EDGE_TYPE, NODE_TYPE>::getNewEdgeIds(
        const std::vector<EdgeType> & edgeIds, std::vector<EdgeType> & newEdgeIds) const {

    newEdgeIds.clear();

    std::vector<std::set<EdgeType>> threadSets(threadpool_.nThreads());

    // find new edges in parallel
    parallel::parallel_foreach(threadpool_, edgeIds.size(), [&](const int tId, const int edgeId){
        auto newEdge = oldToNewEdges_[edgeId];
        if(newEdge != -1) {
            auto & thisSet = threadSets[tId];
            thisSet.insert(newEdge);
        }
    });

    // merge the edge sets
    auto & destSet = threadSets[0];
    for(int tId = 1; tId < threadpool_.nThreads(); ++tId) {
        const auto & srcSet = threadSets[tId];
        destSet.insert(srcSet.begin(), srcSet.end());
    }

    // write edge values to out vector
    newEdgeIds.resize(destSet.size());
    std::copy(destSet.begin(), destSet.end(), newEdgeIds.begin());

}

}
}
<commit_msg>Debugging edgemapping parallelisation<commit_after>#pragma once

#include <algorithm>
#include <map>
#include <vector>

#include "nifty/marray/marray.hxx"
#include "nifty/parallel/threadpool.hxx"

namespace nifty {
namespace tools {

template<class EDGE_TYPE, class NODE_TYPE>
class EdgeMapping {

public:

    typedef EDGE_TYPE EdgeType;
    typedef NODE_TYPE NodeType;
    typedef std::pair<NodeType, NodeType> UvType;
    typedef std::vector<UvType> UvVectorType;

    EdgeMapping(const size_t numberOfEdges, const int nThreads=-1)
        : oldToNewEdges_(numberOfEdges), newUvIds_(), threadpool_(nThreads)
    {}

    void initializeMapping(const marray::View<EdgeType> & uvIds, const std::vector<NodeType> & oldToNewNodes);

    template<class T>
    void mapEdgeValues(const std::vector<T> & edgeValues, std::vector<T> & newEdgeValues) const;

    const UvVectorType & getNewUvIds() const
    {return newUvIds_;}

    void getNewEdgeIds(const std::vector<EdgeType> & edgeIds, std::vector<EdgeType> & newEdgeIds) const;

    size_t numberOfNewEdges() const
    {return newUvIds_.size();}

private:

    //std::map<EdgeType, std::vector<EdgeType>> newToOldEdges_;
    std::vector<EdgeType> oldToNewEdges_;
    UvVectorType newUvIds_;
    mutable parallel::ThreadPool threadpool_;
};

// TODO parallelize ?!
template<class EDGE_TYPE, class NODE_TYPE>
void EdgeMapping<EDGE_TYPE, NODE_TYPE>::initializeMapping(const marray::View<EdgeType> & uvIds, const std::vector<NodeType> & oldToNewNodes)
{
    NodeType uNew, vNew;
    UvType uvNew;
    std::map<UvType, EdgeType> indexMap;
    EdgeType index = 0;

    for(EdgeType i = 0; i < uvIds.shape(0); ++i) {
        uNew = oldToNewNodes[uvIds(i,0)];
        vNew = oldToNewNodes[uvIds(i,1)];

        if(uNew == vNew) {
            oldToNewEdges_[i] = -1;
            continue;
        }

        uvNew = std::make_pair(std::min(uNew, vNew), std::max(uNew, vNew));

        auto e = indexMap.insert(std::make_pair(uvNew, index));
        if(e.second) {
            newUvIds_.push_back(uvNew);
            ++index;
        }

        oldToNewEdges_[i] = e.first->second;
    }

    // FIXME there is some bug in parallelisation
    /*
    typedef std::vector< std::pair<UvType, EdgeType> > newUvToOldEdgeVector;
    std::vector<newUvToOldEdgeVector> threadVectors(threadpool_.nThreads());

    // find new uv ids in parallel
    parallel::parallel_foreach(threadpool_, uvIds.shape(0), [&](const int tId, const EdgeType edgeId){
        NodeType uNew, vNew = oldToNewNodes[uvIds(edgeId, 0)], oldToNewNodes[uvIds(edgeId, 1)];

        if(uNew == vNew) {
            //NOTE this is threadsafe, because we are looping over edgeId in parralel
            oldToNewEdges_[edgeId] = -1;
            return;
        }

        // perform map insertion with hint
        auto & thisVector = threadVectors[tId];
        auto uvNew = std::make_pair(std::min(uNew, vNew), std::max(uNew, vNew));
        thisVector.emplace_back( std::make_pair(uvNew, edgeId) );

    });

    // insert the uv-ids into newUvIds
    // surprisingly, initial benchmarks have shown that the 'find' approach
    // is fastest for keeping the newUvIds unique.
    // TODO benchmark this again properly
    //for(size_t t = 0; t < threadpool_.nThreads(); ++t) {
    //    const auto & thisVector = threadVectors[t];
    //    for(const auto & elem : thisVector) {

    //        if(std::find(newUvIds_.begin(), newUvIds_.end(), elem.first) == newUvIds_.end()) {
    //            newUvIds_.push_back(elem.first);
    //        }
    //    }

    //}
    //std::sort(newUvIds_.begin(), newUvIds_.end());

    // via set TODO unordered
    std::set<UvType> uvNewTmp;
    for(size_t t = 0; t < threadpool_.nThreads(); ++t) {
        const auto & thisVector = threadVectors[t];
        for(const auto & elem : thisVector) {
            uvNewTmp.insert(elem.first);
        }
    }
    newUvIds_.resize(uvNewTmp.size());
    std::copy(uvNewTmp.begin(), uvNewTmp.end(), newUvIds_.begin());

    // construct a lut for the new uv-ids
    std::map<UvType, EdgeType> lut;
    for(EdgeType newEdgeId = 0; newEdgeId < newUvIds_.size(); ++newEdgeId) {
        lut[newUvIds_[newEdgeId]] = newEdgeId;
    }

    // find old to new edges in parallel by going over the unique new uv-ids
    parallel::parallel_foreach(threadpool_, threadpool_.nThreads(), [&](const int tId, const int t){

        const auto & thisVec = threadVectors[t];
        EdgeType newEdgeId;
        for(const auto & elem: thisVec) {
            newEdgeId = lut[elem.first];
            // NOTE: this is thread safe, because every old edge id (== elem.second) only occurs once
            oldToNewEdges_[elem.second] = newEdgeId;
        }

    });
    */

}

template<class EDGE_TYPE, class NODE_TYPE>
template<class T>
void EdgeMapping<EDGE_TYPE, NODE_TYPE>::mapEdgeValues(
        const std::vector<T> & edgeValues, std::vector<T> & newEdgeValues) const {

    NIFTY_CHECK_OP(edgeValues.size(),==,oldToNewEdges_.size(),"Wrong Input size");

    newEdgeValues.clear();
    newEdgeValues.resize(newUvIds_.size(), 0);

    // initialise the thread data
    std::vector<std::vector<T>> threadVecs(threadpool_.nThreads());
    parallel::parallel_foreach(threadpool_, threadpool_.nThreads(), [&](const int t, const int i){
        threadVecs[i] = std::vector<T>(newUvIds_.size(), 0);
    });

    // extract the new edge values in parallel over the old edges
    parallel::parallel_foreach(threadpool_, edgeValues.size(), [&](const int tId, const int edgeId){
        const int64_t newEdge = oldToNewEdges_[edgeId];
        if(newEdge != -1) {
            auto & newVals = threadVecs[tId];
            newVals[newEdge] += edgeValues[edgeId];
        }
    });

    // write to the out vector in parallel over the new edges
    parallel::parallel_foreach(threadpool_, newEdgeValues.size(), [&](const int tId, const int newEdgeId){
        auto & destValue = newEdgeValues[newEdgeId];
        for(int t = 0; t < threadpool_.nThreads(); ++t) {
            auto & srcValues = threadVecs[t];
            destValue += srcValues[newEdgeId];
        }
    });

}

template<class EDGE_TYPE, class NODE_TYPE>
void EdgeMapping<EDGE_TYPE, NODE_TYPE>::getNewEdgeIds(
        const std::vector<EdgeType> & edgeIds, std::vector<EdgeType> & newEdgeIds) const {

    newEdgeIds.clear();

    std::vector<std::set<EdgeType>> threadSets(threadpool_.nThreads());

    // find new edges in parallel
    parallel::parallel_foreach(threadpool_, edgeIds.size(), [&](const int tId, const int edgeId){
        auto newEdge = oldToNewEdges_[edgeId];
        if(newEdge != -1) {
            auto & thisSet = threadSets[tId];
            thisSet.insert(newEdge);
        }
    });

    // merge the edge sets
    auto & destSet = threadSets[0];
    for(int tId = 1; tId < threadpool_.nThreads(); ++tId) {
        const auto & srcSet = threadSets[tId];
        destSet.insert(srcSet.begin(), srcSet.end());
    }

    // write edge values to out vector
    newEdgeIds.resize(destSet.size());
    std::copy(destSet.begin(), destSet.end(), newEdgeIds.begin());

}

}
}
<|endoftext|>


<commit_before><commit_msg>Authors the implementation of ForcePush.<commit_after><|endoftext|>


<commit_before>#include "cmm_socket.h"

struct csocket {
    int osfd;
    u_long cur_label;
    int connected;
};

csocket::csocket(int family, int type, int protocol)
{
    osfd = socket(family, type, protocol);
    if (osfd < 0) {
	/* out of file descriptors or memory at this point */
	throw osfd;
    }
    cur_label = 0;
    connected = 0;
}

csocket::~csocket()
{
    if (osfd > 0) {
	/* if it's a real open socket */
	close(osfd);
    }
}

/* TODO: add parallel option */
mc_socket_t
CMMSocket::create(int family, int type, int protocol)
{
    CMMSocketPtr new_sk;
    try {
	/* automatically clean up if cmm_sock() throws */
	new_sk = new CMMSocketSerial(family, type, protocol));
    } catch (int oserr) {
	return oserr;
    }

    CMMSockHash::accessor ac;
    if (cmm_sock_hash.insert(ac, new_sk->sock)) {
	ac->second = new_sk;
    } else {
	fprintf(stderr, "Error: new socket %d is already in hash!  WTF?\n",
		new_sk->sock);
	assert(0);
    }

    return new_sk->sock;
}

CMMSocketPtr
CMMSocket::lookup(mc_socket_t sock)
{
    CMMSockHash::const_accessor read_ac;
    if (!cmm_sock_hash.find(read_ac, sock)) {
        return CMMSocketPtr(); /* works like NULL */
    } else {
        return read_ac->second;
    }
}

void
CMMSocket::close(mc_socket_t sock)
{
    /* TODO */
}

CMMSocket::CMMSocket(int family, int type, int protocol)
{
    /* reserve a dummy OS file descriptor for this mc_socket. */
    sock = socket(family, type, protocol);
    if (sock < 0) {
	/* invalid params, or no more FDs/memory left. */
	throw sock; /* :-) */
    }

    sock_family = family;
    sock_type = type;
    sock_protocol = protocol;
    addr = NULL;
    addrlen = 0;

    label_down_cb = NULL;
    label_up_cb = NULL;
    cb_arg = NULL;

    /* TODO: read these from /proc instead of hard-coding them. */
    struct csocket *bg_sock = new struct csocket(family, type, protocol);
    struct csocket *ondemand_sock = new struct csocket(family, type, protocol);

    sock_color_hash[CONNMGR_LABEL_BACKGROUND] = bg_sock;
    sock_color_hash[CONNMGR_LABEL_ONDEMAND] = ondemand_sock;
    csocks.push_back(bg_sock);
    csocks.push_back(ondemand_sock);

    /* to illustrate how multiple labels can map to the same interface */
    sock_color_hash[CONNMGR_LABEL_RED] = bg_sock;
    sock_color_hash[CONNMGR_LABEL_BLUE] = ondemand_sock;

    non_blocking=0;
}

CMMSocket::~CMMSocket()
{
    for (CSockList::iterator it = csocks.begin();
	 it != csocks.end(); it++) {
	struct csocket *victim = *it;
	delete victim;
    }

    free(addr);
    close(sock);
}

CMMSocketSerial::CMMSocketSerial()
{
    active_csock = NULL;
}

// XXX: in progress.
void
CMMSocketSerial::prepare(u_long label)
{
    CMMSockHash::const_accessor read_ac;
    CMMSockHash::accessor write_ac;

    if (!cmm_sock_hash.find(read_ac, sock)) {
	assert(0);
    }

    struct csocket *csock = NULL;
    if (up_label) {
	csock = sock_color_hash[up_label];
	if (!csock) {
	    /* caller specified an invalid label */
	    errno = EINVAL;
	    return CMM_FAILED;
	}
    } else {
	if (active_csock) {
	    csock = active_csock;
	    up_label = active_csock->cur_label;
	} else {
	    /* no active csock, no label specified;
	     * just grab the first socket that exists and whose network
	     * is available */
	    for (CSockHash::iterator iter = sock_color_hash.begin();
		 iter != sock_color_hash.end(); iter++) {
		u_long label = iter->first;
		struct csocket *candidate = iter->second;
		if (candidate && scout_net_available(label)) {
		    csock = candidate;
		    up_label = label;
		}
	    }
	}
    }
    if (!csock) {
	errno = ENOTCONN;
	return CMM_FAILED;
    }

    if (!csock->connected) {
#ifdef CMM_TIMING
	struct timeval switch_start;
	struct timeval switch_end;
	struct timeval connect_start;
	struct timeval connect_end;
	struct timeval up_cb_start;
	struct timeval up_cb_end;
	struct timeval diff;

	timerclear(&connect_start);
	timerclear(&connect_end);
	timerclear(&up_cb_start);
	timerclear(&up_cb_end);

	TIME(switch_start);
#endif
	u_long down_label = 0;
	assert(csock->cur_label == 0); /* only for multiplexing */

        //teardown();
        if (active_csock) {
            down_label = active_csock->cur_label;
            read_ac.release();
            if (label_down_cb) {
                /* XXX: check return value? */
                label_down_cb(sock, active_csock->cur_label,
                                  cb_arg);
            }

            if (!cmm_sock_hash.find(write_ac, sock)) {
                assert(0);
            }
            assert(write_ac->second == this);

            close(active_csock->osfd);
            active_csock->osfd = socket(sock_family,
                                            sock_type,
                                            sock_protocol);
            active_csock->cur_label = 0;
            active_csock->connected = 0;
            active_csock = NULL;

        } else {
            read_ac.release();
            if (!cmm_sock_hash.find(write_ac, sock)) {
                assert(0);
            }
            assert(write_ac->second == this);
            assert(csock == sock_color_hash[up_label]);
        }
        // end teardown() code

	setAllSockopts(csock->osfd);

	/* connect new socket with current label */
	set_socket_labels(csock->osfd, up_label);
	fprintf(stderr, "About to connect socket, label=%lu\n", up_label);

        write_ac.release();
        if (!cmm_sock_hash.find(read_ac, sock)) {
            assert(0);
        }
        assert(read_ac->second == this);
        assert(csock == sock_color_hash[up_label]);

#ifdef CMM_TIMING
	TIME(connect_start);
#endif
	int rc = connect(csock->osfd, addr, addrlen);
#ifdef CMM_TIMING
	TIME(connect_end);
#endif
        read_ac.release();
        if (!cmm_sock_hash.find(write_ac, sock)) {
            assert(0);
        }
        assert(write_ac->second == this);
        assert(csock == sock_color_hash[up_label]);

	if (rc < 0) {
	    if(errno==EINPROGRESS || errno==EWOULDBLOCK)
		//is this what we want for the 'send',
		//i.e wait until the sock is conn'ed.
		errno = EAGAIN;
	    else {
		perror("connect");
		close(csock->osfd);
		fprintf(stderr, "libcmm: error connecting new socket\n");
		/* we've previously checked, and the label should be
		 * available... so this failure is something else. */
		/* XXX: maybe check scout_label_available(up_label) again?
		 *      if it is not, return CMM_DEFERRED? */
		/* XXX: this may be a race; i'm not sure. */
#ifdef CMM_TIMING
		TIMEDIFF(connect_start, connect_end, diff);
		fprintf(timing_file, "connect() failed after %ld.%06ld seconds\n",
			diff.tv_sec, diff.tv_usec);
#endif
		return CMM_FAILED;
	    }
	}

	csock->cur_label = up_label;
	csock->connected = 1;
#ifdef IMPORT_RULES
	connecting = 1;
#endif
	active_csock = csock;
	write_ac.release();

	if (label_up_cb) {
#ifdef CMM_TIMING
	    TIME(up_cb_start);
#endif
	    int rc = label_up_cb(sock, up_label, cb_arg);
#ifdef CMM_TIMING
	    TIME(up_cb_end);
#endif
#ifdef IMPORT_RULES
	    if (cmm_sock_hash.find(write_ac, sock)) {
		assert(write_ac->second == this);
		connecting = 0;
		write_ac.release();
	    }
#endif

	    if (rc < 0) {
#ifdef CMM_TIMING
		TIMEDIFF(up_cb_start, up_cb_end, diff);
		fprintf(timing_file,
			"error: application-level up_cb failed"
			"after %ld.%06ld\n",
			diff.tv_sec, diff.tv_usec);
#endif
		fprintf(stderr, "error: application-level up_cb failed\n");

		if (rc == CMM_DEFERRED) {
		    return rc;
		} else {
		    CMMSockHash::accessor write_ac;
		    if (cmm_sock_hash.find(write_ac, sock)) {
			assert(write_ac->second == this);
			assert(csock == sock_color_hash[up_label]);

			close(csock->osfd);
			csock->osfd = socket(sock_family,
					     sock_type,
					     sock_protocol);
			csock->cur_label = 0;
			csock->connected = 0;
			active_csock = NULL;
		    } /* else: must have already been cmm_close()d */

		    return CMM_FAILED;
		}
	    }
	}
#ifdef CMM_TIMING
	TIME(switch_end);
	{
	    tbb::mutex::scoped_lock(timing_mutex);

	    if (timing_file) {
		TIMEDIFF(switch_start, switch_end, diff);
		struct timeval tmp = total_switch_time;
		timeradd(&tmp, &diff, &total_switch_time);
		if (down_label == CONNMGR_LABEL_BACKGROUND &&
		    up_label == CONNMGR_LABEL_ONDEMAND) {
		    num_switches_to_fg++;
		    tmp = total_switch_time_to_fg;
		    timeradd(&tmp, &diff, &total_switch_time_to_fg);
		} else if (down_label == CONNMGR_LABEL_ONDEMAND &&
			   up_label == CONNMGR_LABEL_BACKGROUND) {
		    num_switches_to_bg++;
		    tmp = total_switch_time_to_bg;
		    timeradd(&tmp, &diff, &total_switch_time_to_bg);
		}

		fprintf(timing_file, "Switch %d at %ld.%06ld: %ld.%06ld; from %s to %s; ",
			++num_switches,
			switch_start.tv_sec, switch_start.tv_usec,
			diff.tv_sec, diff.tv_usec,
			label_str(down_label), label_str(up_label));
		if (connect_start.tv_sec > 0) {
		    TIMEDIFF(connect_start, connect_end, diff);
		    fprintf(timing_file, "connect(): %ld.%06ld; ",
			    diff.tv_sec, diff.tv_usec);
		    struct timeval tmp = total_time_in_connect;
		    timeradd(&tmp, &diff, &total_time_in_connect);
		}
		if (up_cb_start.tv_sec > 0) {
		    TIMEDIFF(up_cb_start, up_cb_end, diff);
		    fprintf(timing_file, "up_cb(): %ld.%06ld",
			    diff.tv_sec, diff.tv_usec);
		    struct timeval tmp = total_time_in_up_cb;
		    timeradd(&tmp, &diff, &total_time_in_up_cb);
		}
		fprintf(timing_file, "\n");
	    }
	}
#endif
    } /* if (!csock->connected) */

    return 0;
}

/* these are all sockopts that have succeeded in the past.
 * for now, let's assume they succeed again.
 * this may be invalid; maybe some sockopts succeed on one interface
 * but fail on another?  not sure. XXX */
/* REQ: call with write lock on this cmm_sock */
int
CMMSocket::setAllSockopts(int osfd)
{
    if (osfd != -1) {
	for (SockOptHash::const_iterator i = sockopts.begin(); i != sockopts.end(); i++) {
	    int level = i->first;
	    const SockOptNames &optnames = i->second;
	    for (SockOptNames::const_iterator j = optnames.begin();
		 j != optnames.end(); j++) {
		int optname = j->first;
		const struct sockopt &opt = j->second;
		int rc = setsockopt(osfd, level, optname,
				    opt.optval, opt.optlen);
		if (rc < 0) {
		    return rc;
		}
	    }
	}
    }

    return 0;
}

void CMMSocketSerial::teardown(u_long down_label)
{
    CMMSockHash::const_accessor read_ac;
    if (!cmm_sock_hash.find(read_ac, sock)) {
	assert(0);
    }
    assert(read_ac->second == this);

    if (sk->active_csock &&
	sk->active_csock->cur_label & down_label) {
	if (sk->label_down_cb) {
	    read_ac.release();
	    sk->label_down_cb(sk->sock, sk->active_csock->cur_label,
			      sk->cb_arg);
	} else {
	    read_ac.release();
	}

	CMMSockHash::accessor write_ac;
	if (!cmm_sock_hash.find(write_ac, sk_iter->first)) {
	    assert(0);
	}
	assert(sk == write_ac->second);

	/* the down handler may have reconnected the socket,
	 * so make sure not to close it in that case */
	if (sk->active_csock->cur_label & down_label) {
	    close(sk->active_csock->osfd);
	    sk->active_csock->osfd = socket(sk->sock_family,
					    sk->sock_type,
					    sk->sock_protocol);
	    sk->active_csock->cur_label = 0;
	    sk->active_csock->connected = 0;
	    sk->active_csock = NULL;
	}
    }
}
<commit_msg>sync; filled in CMMSocket::close<commit_after>#include "cmm_socket.h"

struct csocket {
    int osfd;
    u_long cur_label;
    int connected;
};

csocket::csocket(int family, int type, int protocol)
{
    osfd = socket(family, type, protocol);
    if (osfd < 0) {
	/* out of file descriptors or memory at this point */
	throw osfd;
    }
    cur_label = 0;
    connected = 0;
}

csocket::~csocket()
{
    if (osfd > 0) {
	/* if it's a real open socket */
	close(osfd);
    }
}

/* TODO: add parallel option */
mc_socket_t
CMMSocket::create(int family, int type, int protocol)
{
    CMMSocketPtr new_sk;
    try {
	/* automatically clean up if cmm_sock() throws */
	new_sk = new CMMSocketSerial(family, type, protocol));
    } catch (int oserr) {
	return oserr;
    }

    CMMSockHash::accessor ac;
    if (cmm_sock_hash.insert(ac, new_sk->sock)) {
	ac->second = new_sk;
    } else {
	fprintf(stderr, "Error: new socket %d is already in hash!  WTF?\n",
		new_sk->sock);
	assert(0);
    }

    return new_sk->sock;
}

CMMSocketPtr
CMMSocket::lookup(mc_socket_t sock)
{
    CMMSockHash::const_accessor read_ac;
    if (!cmm_sock_hash.find(read_ac, sock)) {
        return CMMSocketPtr(); /* works like NULL */
    } else {
        return read_ac->second;
    }
}

void
CMMSocket::close(mc_socket_t sock)
{
    CMMSockHash::accessor ac;
    if (cmm_sock_hash.find(ac, sock)) {
	struct cmm_sock *sk = ac->second;
	cmm_sock_hash.erase(ac);
	ac.release();

	assert(sk);

	delete sk; /* moved the rest of the cleanup to the destructor */
	return 0;
    } else {
	fprintf(stderr, "Warning: cmm_close()ing a socket that's not "
		"in my hash\n");
	errno = EBADF;
	return -1;
    }
}

CMMSocket::CMMSocket(int family, int type, int protocol)
{
    /* reserve a dummy OS file descriptor for this mc_socket. */
    sock = socket(family, type, protocol);
    if (sock < 0) {
	/* invalid params, or no more FDs/memory left. */
	throw sock; /* :-) */
    }

    sock_family = family;
    sock_type = type;
    sock_protocol = protocol;
    addr = NULL;
    addrlen = 0;

    label_down_cb = NULL;
    label_up_cb = NULL;
    cb_arg = NULL;

    /* TODO: read these from /proc instead of hard-coding them. */
    struct csocket *bg_sock = new struct csocket(family, type, protocol);
    struct csocket *ondemand_sock = new struct csocket(family, type, protocol);

    sock_color_hash[CONNMGR_LABEL_BACKGROUND] = bg_sock;
    sock_color_hash[CONNMGR_LABEL_ONDEMAND] = ondemand_sock;
    csocks.push_back(bg_sock);
    csocks.push_back(ondemand_sock);

    /* to illustrate how multiple labels can map to the same interface */
    sock_color_hash[CONNMGR_LABEL_RED] = bg_sock;
    sock_color_hash[CONNMGR_LABEL_BLUE] = ondemand_sock;

    non_blocking=0;
}

CMMSocket::~CMMSocket()
{
    for (CSockList::iterator it = csocks.begin();
	 it != csocks.end(); it++) {
	struct csocket *victim = *it;
	delete victim;
    }

    free(addr);
    close(sock);
}

CMMSocketSerial::CMMSocketSerial()
{
    active_csock = NULL;
}

// XXX: in progress.
void
CMMSocketSerial::prepare(u_long label)
{
    CMMSockHash::const_accessor read_ac;
    CMMSockHash::accessor write_ac;

    if (!cmm_sock_hash.find(read_ac, sock)) {
	assert(0);
    }

    struct csocket *csock = NULL;
    if (up_label) {
	csock = sock_color_hash[up_label];
	if (!csock) {
	    /* caller specified an invalid label */
	    errno = EINVAL;
	    return CMM_FAILED;
	}
    } else {
	if (active_csock) {
	    csock = active_csock;
	    up_label = active_csock->cur_label;
	} else {
	    /* no active csock, no label specified;
	     * just grab the first socket that exists and whose network
	     * is available */
	    for (CSockHash::iterator iter = sock_color_hash.begin();
		 iter != sock_color_hash.end(); iter++) {
		u_long label = iter->first;
		struct csocket *candidate = iter->second;
		if (candidate && scout_net_available(label)) {
		    csock = candidate;
		    up_label = label;
		}
	    }
	}
    }
    if (!csock) {
	errno = ENOTCONN;
	return CMM_FAILED;
    }

    if (!csock->connected) {
#ifdef CMM_TIMING
	struct timeval switch_start;
	struct timeval switch_end;
	struct timeval connect_start;
	struct timeval connect_end;
	struct timeval up_cb_start;
	struct timeval up_cb_end;
	struct timeval diff;

	timerclear(&connect_start);
	timerclear(&connect_end);
	timerclear(&up_cb_start);
	timerclear(&up_cb_end);

	TIME(switch_start);
#endif
	u_long down_label = 0;
	assert(csock->cur_label == 0); /* only for multiplexing */

        //teardown();
        if (active_csock) {
            down_label = active_csock->cur_label;
            read_ac.release();
            if (label_down_cb) {
                /* XXX: check return value? */
                label_down_cb(sock, active_csock->cur_label,
                                  cb_arg);
            }

            if (!cmm_sock_hash.find(write_ac, sock)) {
                assert(0);
            }
            assert(write_ac->second == this);

            close(active_csock->osfd);
            active_csock->osfd = socket(sock_family,
                                            sock_type,
                                            sock_protocol);
            active_csock->cur_label = 0;
            active_csock->connected = 0;
            active_csock = NULL;

        } else {
            read_ac.release();
            if (!cmm_sock_hash.find(write_ac, sock)) {
                assert(0);
            }
            assert(write_ac->second == this);
            assert(csock == sock_color_hash[up_label]);
        }
        // end teardown() code

	setAllSockopts(csock->osfd);

	/* connect new socket with current label */
	set_socket_labels(csock->osfd, up_label);
	fprintf(stderr, "About to connect socket, label=%lu\n", up_label);

        write_ac.release();
        if (!cmm_sock_hash.find(read_ac, sock)) {
            assert(0);
        }
        assert(read_ac->second == this);
        assert(csock == sock_color_hash[up_label]);

#ifdef CMM_TIMING
	TIME(connect_start);
#endif
	int rc = connect(csock->osfd, addr, addrlen);
#ifdef CMM_TIMING
	TIME(connect_end);
#endif
        read_ac.release();
        if (!cmm_sock_hash.find(write_ac, sock)) {
            assert(0);
        }
        assert(write_ac->second == this);
        assert(csock == sock_color_hash[up_label]);

	if (rc < 0) {
	    if(errno==EINPROGRESS || errno==EWOULDBLOCK)
		//is this what we want for the 'send',
		//i.e wait until the sock is conn'ed.
		errno = EAGAIN;
	    else {
		perror("connect");
		close(csock->osfd);
		fprintf(stderr, "libcmm: error connecting new socket\n");
		/* we've previously checked, and the label should be
		 * available... so this failure is something else. */
		/* XXX: maybe check scout_label_available(up_label) again?
		 *      if it is not, return CMM_DEFERRED? */
		/* XXX: this may be a race; i'm not sure. */
#ifdef CMM_TIMING
		TIMEDIFF(connect_start, connect_end, diff);
		fprintf(timing_file, "connect() failed after %ld.%06ld seconds\n",
			diff.tv_sec, diff.tv_usec);
#endif
		return CMM_FAILED;
	    }
	}

	csock->cur_label = up_label;
	csock->connected = 1;
#ifdef IMPORT_RULES
	connecting = 1;
#endif
	active_csock = csock;
	write_ac.release();

	if (label_up_cb) {
#ifdef CMM_TIMING
	    TIME(up_cb_start);
#endif
	    int rc = label_up_cb(sock, up_label, cb_arg);
#ifdef CMM_TIMING
	    TIME(up_cb_end);
#endif
#ifdef IMPORT_RULES
	    if (cmm_sock_hash.find(write_ac, sock)) {
		assert(write_ac->second == this);
		connecting = 0;
		write_ac.release();
	    }
#endif

	    if (rc < 0) {
#ifdef CMM_TIMING
		TIMEDIFF(up_cb_start, up_cb_end, diff);
		fprintf(timing_file,
			"error: application-level up_cb failed"
			"after %ld.%06ld\n",
			diff.tv_sec, diff.tv_usec);
#endif
		fprintf(stderr, "error: application-level up_cb failed\n");

		if (rc == CMM_DEFERRED) {
		    return rc;
		} else {
		    CMMSockHash::accessor write_ac;
		    if (cmm_sock_hash.find(write_ac, sock)) {
			assert(write_ac->second == this);
			assert(csock == sock_color_hash[up_label]);

			close(csock->osfd);
			csock->osfd = socket(sock_family,
					     sock_type,
					     sock_protocol);
			csock->cur_label = 0;
			csock->connected = 0;
			active_csock = NULL;
		    } /* else: must have already been cmm_close()d */

		    return CMM_FAILED;
		}
	    }
	}
#ifdef CMM_TIMING
	TIME(switch_end);
	{
	    tbb::mutex::scoped_lock(timing_mutex);

	    if (timing_file) {
		TIMEDIFF(switch_start, switch_end, diff);
		struct timeval tmp = total_switch_time;
		timeradd(&tmp, &diff, &total_switch_time);
		if (down_label == CONNMGR_LABEL_BACKGROUND &&
		    up_label == CONNMGR_LABEL_ONDEMAND) {
		    num_switches_to_fg++;
		    tmp = total_switch_time_to_fg;
		    timeradd(&tmp, &diff, &total_switch_time_to_fg);
		} else if (down_label == CONNMGR_LABEL_ONDEMAND &&
			   up_label == CONNMGR_LABEL_BACKGROUND) {
		    num_switches_to_bg++;
		    tmp = total_switch_time_to_bg;
		    timeradd(&tmp, &diff, &total_switch_time_to_bg);
		}

		fprintf(timing_file, "Switch %d at %ld.%06ld: %ld.%06ld; from %s to %s; ",
			++num_switches,
			switch_start.tv_sec, switch_start.tv_usec,
			diff.tv_sec, diff.tv_usec,
			label_str(down_label), label_str(up_label));
		if (connect_start.tv_sec > 0) {
		    TIMEDIFF(connect_start, connect_end, diff);
		    fprintf(timing_file, "connect(): %ld.%06ld; ",
			    diff.tv_sec, diff.tv_usec);
		    struct timeval tmp = total_time_in_connect;
		    timeradd(&tmp, &diff, &total_time_in_connect);
		}
		if (up_cb_start.tv_sec > 0) {
		    TIMEDIFF(up_cb_start, up_cb_end, diff);
		    fprintf(timing_file, "up_cb(): %ld.%06ld",
			    diff.tv_sec, diff.tv_usec);
		    struct timeval tmp = total_time_in_up_cb;
		    timeradd(&tmp, &diff, &total_time_in_up_cb);
		}
		fprintf(timing_file, "\n");
	    }
	}
#endif
    } /* if (!csock->connected) */

    return 0;
}

/* these are all sockopts that have succeeded in the past.
 * for now, let's assume they succeed again.
 * this may be invalid; maybe some sockopts succeed on one interface
 * but fail on another?  not sure. XXX */
/* REQ: call with write lock on this cmm_sock */
int
CMMSocket::setAllSockopts(int osfd)
{
    if (osfd != -1) {
	for (SockOptHash::const_iterator i = sockopts.begin(); i != sockopts.end(); i++) {
	    int level = i->first;
	    const SockOptNames &optnames = i->second;
	    for (SockOptNames::const_iterator j = optnames.begin();
		 j != optnames.end(); j++) {
		int optname = j->first;
		const struct sockopt &opt = j->second;
		int rc = setsockopt(osfd, level, optname,
				    opt.optval, opt.optlen);
		if (rc < 0) {
		    return rc;
		}
	    }
	}
    }

    return 0;
}

void CMMSocketSerial::teardown(u_long down_label)
{
    CMMSockHash::const_accessor read_ac;
    if (!cmm_sock_hash.find(read_ac, sock)) {
	assert(0);
    }
    assert(read_ac->second == this);

    if (sk->active_csock &&
	sk->active_csock->cur_label & down_label) {
	if (sk->label_down_cb) {
	    read_ac.release();
	    sk->label_down_cb(sk->sock, sk->active_csock->cur_label,
			      sk->cb_arg);
	} else {
	    read_ac.release();
	}

	CMMSockHash::accessor write_ac;
	if (!cmm_sock_hash.find(write_ac, sk_iter->first)) {
	    assert(0);
	}
	assert(sk == write_ac->second);

	/* the down handler may have reconnected the socket,
	 * so make sure not to close it in that case */
	if (sk->active_csock->cur_label & down_label) {
	    close(sk->active_csock->osfd);
	    sk->active_csock->osfd = socket(sk->sock_family,
					    sk->sock_type,
					    sk->sock_protocol);
	    sk->active_csock->cur_label = 0;
	    sk->active_csock->connected = 0;
	    sk->active_csock = NULL;
	}
    }
}
<|endoftext|>


<commit_before>#pragma once

#include <tudocomp/def.hpp>
#include <tudocomp/util.hpp>
#include <tudocomp/ds/IntVector.hpp>

namespace tdc {

template<class array_t>
class ArrayMaxHeap {

private:
    enum perlocation_dir_t {
        NONE,
        LEFT,
        RIGHT
    };

    static inline len_t lc(len_t i) {
        return 2*i+1;
    }

    static inline len_t rc(len_t i) {
        return 2*i+2;
    }

    static inline len_t parent(len_t i) {
        return (i-1)/2;
    }

    // the array
    array_t* m_array;

    // undefined position in heap
    size_t m_undef;

    // heap
    size_t m_size;
    DynamicIntVector m_heap;

    // back mapping
    DynamicIntVector m_pos;

    inline void put(size_t pos, len_t i) {
        m_heap[pos] = i;
        m_pos[i] = pos;
    }

public:
    /// Constructor
    inline ArrayMaxHeap(array_t& array, const size_t array_size, const size_t heap_size)
        : m_array(&array), m_size(0)
	{
        /*size_t num_entries = 0;
        for(size_t i = 1; i < n; i++) {
            if(lcp[i] >= min_lcp) ++num_entries;
        }*/

        m_heap = DynamicIntVector(heap_size, 0, bits_for(array_size-1));
        m_undef = heap_size;
        m_pos = DynamicIntVector(array_size, m_undef, bits_for(m_undef));

        //Construct heap
        /*for(size_t i = 1; i < n; i++) {
            if(lcp[i] >= min_lcp) insert(i);
        }*/
    }

    /// Insert array item with index i into heap.
    inline void insert(len_t i) {
        size_t pos = m_size++;

        // perlocate up
        auto lcp_i = (*m_array)[i];
        while(pos > 0 && lcp_i > (*m_array)[m_heap[parent(pos)]]) {
            put(pos, m_heap[parent(pos)]);
            pos = parent(pos);
        }

        put(pos, i);
    }

private:
    inline void perlocate_down(size_t pos, len_t k) {
        auto lcp_k = (*m_array)[k];

        perlocation_dir_t dir = NONE;
        do {
            len_t lcp_lc = (lc(pos) < m_size) ? (*m_array)[m_heap[lc(pos)]] : 0;
            len_t lcp_rc = (rc(pos) < m_size) ? (*m_array)[m_heap[rc(pos)]] : 0;

            // find perlocation direction
            if(lcp_k < lcp_lc && lcp_k < lcp_rc) {
                // both children are larger, pick the largest
                dir = (lcp_lc > lcp_rc) ? LEFT : RIGHT;
            } else if(lcp_k < lcp_lc) {
                // go to the left
                dir = LEFT;
            } else if(lcp_k < lcp_rc) {
                // go to the right
                dir = RIGHT;
            } else {
                dir = NONE;
            }

            // go down if necessary
            if(dir == LEFT) {
                // left
                put(pos, m_heap[lc(pos)]);
                pos = lc(pos);
            } else if(dir == RIGHT) {
                // right
                put(pos, m_heap[rc(pos)]);
                pos = rc(pos);
            }
        } while(dir != NONE);

        put(pos, k);
    }

public:
    /// Remove array item with index i from heap.
    inline void remove(len_t i) {
        auto pos = m_pos[i];
        if(pos != m_undef) {
            // get last element in heap
            auto k = m_heap[--m_size];

            // perlocate it down, starting at the former position of i
            perlocate_down(pos, k);
        }

        m_pos[i] = m_undef; // i was removed
    }

    /// Decrease key on array item with index i.
    template<typename T>
    inline void decrease_key(len_t i, T value) {
        (*m_array)[i] = value;

        auto pos = m_pos[i];
        if(pos != m_undef) {
            // perlocate item down, starting at its current position
            perlocate_down(pos, i);
        }
    }

    /// Checks whether or not array item i is contained in this heap.
    inline bool contains(len_t i) const {
        return m_pos[i] != m_undef;
    }

    /// Get number of contained entries.
    inline size_t size() const {
        return m_size;
    }

    /// Get first item (index of array item with highest value)
    inline size_t get_max() const {
        return m_heap[0];
    }

    // for tests?
    inline bool is_valid() const {
        for(size_t i = 0; i < m_size; i++) {
            auto lcp_i = (*m_array)[m_heap[i]];
            if(lc(i) < m_size) DCHECK(lcp_i >= (*m_array)[m_heap[lc(i)]]);
            if(rc(i) < m_size) DCHECK(lcp_i >= (*m_array)[m_heap[rc(i)]]);
        }

        return true;
    }
};

} //ns

<commit_msg>ArrayHeap +key method<commit_after>#pragma once

#include <tudocomp/def.hpp>
#include <tudocomp/util.hpp>
#include <tudocomp/ds/IntVector.hpp>

namespace tdc {

template<class array_t>
class ArrayMaxHeap {

private:
    enum perlocation_dir_t {
        NONE,
        LEFT,
        RIGHT
    };

    static inline len_t lc(len_t i) {
        return 2*i+1;
    }

    static inline len_t rc(len_t i) {
        return 2*i+2;
    }

    static inline len_t parent(len_t i) {
        return (i-1)/2;
    }

    // the array
    array_t* m_array;

    // undefined position in heap
    size_t m_undef;

    // heap
    size_t m_size;
    DynamicIntVector m_heap;

    // back mapping
    DynamicIntVector m_pos;

    inline void put(size_t pos, len_t i) {
        m_heap[pos] = i;
        m_pos[i] = pos;
    }

public:
    /// Constructor
    inline ArrayMaxHeap(array_t& array, const size_t array_size, const size_t heap_size)
        : m_array(&array), m_size(0)
	{
        /*size_t num_entries = 0;
        for(size_t i = 1; i < n; i++) {
            if(lcp[i] >= min_lcp) ++num_entries;
        }*/

        m_heap = DynamicIntVector(heap_size, 0, bits_for(array_size-1));
        m_undef = heap_size;
        m_pos = DynamicIntVector(array_size, m_undef, bits_for(m_undef));

        //Construct heap
        /*for(size_t i = 1; i < n; i++) {
            if(lcp[i] >= min_lcp) insert(i);
        }*/
    }

    /// Insert array item with index i into heap.
    inline void insert(len_t i) {
        size_t pos = m_size++;

        // perlocate up
        auto lcp_i = (*m_array)[i];
        while(pos > 0 && lcp_i > (*m_array)[m_heap[parent(pos)]]) {
            put(pos, m_heap[parent(pos)]);
            pos = parent(pos);
        }

        put(pos, i);
    }

private:
    inline void perlocate_down(size_t pos, len_t k) {
        auto lcp_k = (*m_array)[k];

        perlocation_dir_t dir = NONE;
        do {
            len_t lcp_lc = (lc(pos) < m_size) ? (*m_array)[m_heap[lc(pos)]] : 0;
            len_t lcp_rc = (rc(pos) < m_size) ? (*m_array)[m_heap[rc(pos)]] : 0;

            // find perlocation direction
            if(lcp_k < lcp_lc && lcp_k < lcp_rc) {
                // both children are larger, pick the largest
                dir = (lcp_lc > lcp_rc) ? LEFT : RIGHT;
            } else if(lcp_k < lcp_lc) {
                // go to the left
                dir = LEFT;
            } else if(lcp_k < lcp_rc) {
                // go to the right
                dir = RIGHT;
            } else {
                dir = NONE;
            }

            // go down if necessary
            if(dir == LEFT) {
                // left
                put(pos, m_heap[lc(pos)]);
                pos = lc(pos);
            } else if(dir == RIGHT) {
                // right
                put(pos, m_heap[rc(pos)]);
                pos = rc(pos);
            }
        } while(dir != NONE);

        put(pos, k);
    }

public:
    /// Remove array item with index i from heap.
    inline void remove(len_t i) {
        auto pos = m_pos[i];
        if(pos != m_undef) {
            // get last element in heap
            auto k = m_heap[--m_size];

            // perlocate it down, starting at the former position of i
            perlocate_down(pos, k);
        }

        m_pos[i] = m_undef; // i was removed
    }

    /// Decrease key on array item with index i.
    template<typename T>
    inline void decrease_key(len_t i, T value) {
        (*m_array)[i] = value;

        auto pos = m_pos[i];
        if(pos != m_undef) {
            // perlocate item down, starting at its current position
            perlocate_down(pos, i);
        }
    }

    /// Checks whether or not array item i is contained in this heap.
    inline bool contains(len_t i) const {
        return m_pos[i] != m_undef;
    }

    /// Get number of contained entries.
    inline size_t size() const {
        return m_size;
    }

    /// Get first item (index of array item with highest value)
    inline size_t get_max() const {
        return m_heap[0];
    }

    // for tests?
    inline bool is_valid() const {
        for(size_t i = 0; i < m_size; i++) {
            auto lcp_i = (*m_array)[m_heap[i]];
            if(lc(i) < m_size) DCHECK(lcp_i >= (*m_array)[m_heap[lc(i)]]);
            if(rc(i) < m_size) DCHECK(lcp_i >= (*m_array)[m_heap[rc(i)]]);
        }

        return true;
    }
    inline len_t key(len_t value) const {
        return (*m_array)[value];
    }
};

} //ns

<|endoftext|>


<commit_before>// -----------------------------------------------------------------------------
// Copyright 2016 Marco Biasini
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -----------------------------------------------------------------------------
#ifndef TYPUS_ASYNC_STATE_MACHINE_HH
#define TYPUS_ASYNC_STATE_MACHINE_HH

#include <atomic>

namespace typus {

/**
 * Helper class for implementing asynchronous state machines
 *
 * The asynchronous state machine distinguishes between two types of states.
 * Transition states and stationary states. Transition states are used to
 * transition from one stationary state to another, in case the transition is an
 * asynchronous operation. Examples of such transitions include establishing a
 * network connection, or starting an external device. When in a transition
 * state, further requested state changes are delayed until the ongoing transition
 * finishes.
 */
template <typename State, typename Derived>
class async_state_machine {
public:

    async_state_machine(State initial):
        desired_(initial),
        current_(initial) {
    }

    State desired_state() const {
        return desired_.load(std::memory_order_relaxed);
    }

    State current_state() const {
        return current.load(std::memory_order_relaxed);
    }

    void set_desired_state(State desired) {
        desired_.store(desired, std::memory_order_relaxed);
        State current = this->current_state();
        if (current == desired || is_transition_state(current)) {
            return;
        }
        this->as_derived().update_state(current, desired);
    }

protected:
    bool begin_transition(State from_state, State transition_state) {
        return current_.compare_exchange(from_state, transition_state);
    }

    void end_transition(State end_state) {
        current_.store(end_state, std::memory_order_relaxed);
        this->set_desired_state(end_state);
    }

private:
    Derived &as_derived() { return static_cast<Derived&>(&this); }
    const Derived &as_derived() const { return static_cast<Derived&>(&this); }

    std::atomic<State> desired_;
    std::atomic<State> current_;

}

}

#endif // TYPUS_ASYNC_STATE_MACHINE
<commit_msg>remove async state machine<commit_after><|endoftext|>


<commit_before>//============================================================================
// vSMC/include/vsmc/rng/internal/common.hpp
//----------------------------------------------------------------------------
//                         vSMC: Scalable Monte Carlo
//----------------------------------------------------------------------------
// Copyright (c) 2013-2015, Yan Zhou
// 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.
//
// 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.
//============================================================================

#ifndef VSMC_RNG_INTERNAL_COMMON_HPP
#define VSMC_RNG_INTERNAL_COMMON_HPP

#include <vsmc/internal/common.hpp>

#ifndef UINT64_C
#error __STDC_CONSTANT_MACROS not defined before #<stdint.h>
#endif

#define VSMC_DEFINE_RNG_DISTRIBUTION_OPERATORS                                \
    param_type param() const { return param_; }                               \
    void param(const param_type &par) { param_ = par; }                       \
    void reset() { param_.reset(); }                                          \
                                                                              \
    friend bool operator==(                                                   \
        const distribution_type &dist1, const distribution_type &dist2)       \
    {                                                                         \
        return dist1.param() == dist2.param();                                \
    }                                                                         \
                                                                              \
    friend bool operator!=(                                                   \
        const distribution_type &dist1, const distribution_type &dist2)       \
    {                                                                         \
        return dist1.param() != dist2.param();                                \
    }                                                                         \
                                                                              \
    template <typename CharT, typename Traits>                                \
    friend std::basic_ostream<CharT, Traits> &operator<<(                     \
        std::basic_ostream<CharT, Traits> &os, const distribution_type &dist) \
    {                                                                         \
        os << dist.param();                                                   \
                                                                              \
        return os;                                                            \
    }                                                                         \
                                                                              \
    template <typename CharT, typename Traits>                                \
    friend std::basic_istream<CharT, Traits> &operator>>(                     \
        std::basic_istream<CharT, Traits> &is, distribution_type &dist)       \
    {                                                                         \
        param_type param;                                                     \
        is >> param;                                                          \
        if (is.good())                                                        \
            dist.param(std::move(param));                                     \
                                                                              \
        return is;                                                            \
    }

namespace vsmc
{

namespace internal
{

VSMC_DEFINE_TYPE_DISPATCH_TRAIT(KeyType, key_type, NullType)

template <typename RealType>
bool is_equal(RealType a, RealType b)
{
    if (a > b || a < b)
        return false;
    return true;
}

template <int N>
class RNGBitsNMax
{
    public:
    static constexpr std::uint64_t value = VSMC_MAX_UINT(std::uint64_t) >>
        (64 - N);
}; // class RNGBitsNMax

template <typename RNGType, int N>
class RNGBitsN
{
    static constexpr std::uint64_t umax = RNGType::max VSMC_MNE();
    static constexpr std::uint64_t bmax = RNGBitsNMax<N>::value;

    public:
    static constexpr int value =
        umax < bmax ? RNGBitsN<RNGType, N - 1>::value : N;
}; // class RNGBitsN

template <typename RNGType>
class RNGBitsN<RNGType, 0>
{
    public:
    static constexpr int value = 0;
}; // class RNGBitsN

template <typename RNGType>
class RNGBits : public RNGBitsN<RNGType, 64>
{
}; // class RNGBits

template <typename SeedSeq, typename U, typename V = U, typename W = V>
class is_seed_seq
    : public std::integral_constant<bool,
          !std::is_convertible<SeedSeq, U>::value &&
              !std::is_convertible<SeedSeq, V>::value &&
              !std::is_convertible<SeedSeq, W>::value &&
              !std::is_same<typename std::remove_cv<SeedSeq>::type,
                  U>::value &&
              !std::is_same<typename std::remove_cv<SeedSeq>::type,
                  V>::value &&
              !std::is_same<typename std::remove_cv<SeedSeq>::type, W>::value>
{
}; // class is_seed_seq

template <std::size_t, typename T, std::size_t K>
inline static void increment_single(std::array<T, K> &ctr, std::false_type)
{
    ++ctr.back();
}

template <std::size_t N, typename T, std::size_t K>
inline static void increment_single(std::array<T, K> &ctr, std::true_type)
{
    if (++std::get<N>(ctr) != 0)
        return;

    increment_single<N + 1>(ctr, std::integral_constant<bool, N + 2 < K>());
}

template <typename T, std::size_t K>
inline void increment(std::array<T, K> &ctr)
{
    increment_single<0>(ctr, std::integral_constant<bool, 1 < K>());
}

template <typename T, std::size_t K, T NSkip>
inline void increment(std::array<T, K> &ctr, std::integral_constant<T, NSkip>)
{
    T old = ctr.front();
    ctr.front() += NSkip;

    if (ctr.front() < old && old != 0)
        increment_single<1>(ctr, std::integral_constant<bool, 2 < K>());
}

template <typename T, std::size_t K>
inline static void increment(std::array<T, K> &ctr, T nskip)
{
    T old = ctr.front();
    ctr.front() += nskip;

    if (ctr.front() < old && old != 0)
        increment_single<1>(ctr, std::integral_constant<bool, 2 < K>());
}

template <std::size_t Blocks, std::size_t, typename T, std::size_t K>
inline static void increment_block(std::array<T, K> &,
    std::array<std::array<T, K>, Blocks> &, std::false_type)
{
}

template <std::size_t Blocks, std::size_t B, typename T, std::size_t K>
inline static void increment_block(std::array<T, K> &ctr,
    std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
{
    std::get<B>(ctr_block) = ctr;
    increment(std::get<B>(ctr_block), std::integral_constant<T, B + 1>());
    increment_block<Blocks, B + 1>(
        ctr, ctr_block, std::integral_constant<bool, B + 1 < Blocks>());
}

template <std::size_t Blocks, typename T, std::size_t K>
static void increment(
    std::array<T, K> &ctr, std::array<std::array<T, K>, Blocks> &ctr_block)
{
    increment_block<Blocks, 0>(
        ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
    ctr = ctr_block.back();
}

} // namespace vsmc::internal

template <typename RNGType>
void rng_rand(RNGType &rng, std::size_t n, typename RNGType::result_type *r)
{
    for (std::size_t i = 0; i != n; ++i)
        r[i] = rng();
}

} // namespace vsmc

#endif // VSMC_RNG_INTERNAL_COMMON_HPP
<commit_msg>improve perforamnce of increment blocks<commit_after>//============================================================================
// vSMC/include/vsmc/rng/internal/common.hpp
//----------------------------------------------------------------------------
//                         vSMC: Scalable Monte Carlo
//----------------------------------------------------------------------------
// Copyright (c) 2013-2015, Yan Zhou
// 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.
//
// 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.
//============================================================================

#ifndef VSMC_RNG_INTERNAL_COMMON_HPP
#define VSMC_RNG_INTERNAL_COMMON_HPP

#include <vsmc/internal/common.hpp>

#ifndef UINT64_C
#error __STDC_CONSTANT_MACROS not defined before #<stdint.h>
#endif

#define VSMC_DEFINE_RNG_DISTRIBUTION_OPERATORS                                \
    param_type param() const { return param_; }                               \
    void param(const param_type &par) { param_ = par; }                       \
    void reset() { param_.reset(); }                                          \
                                                                              \
    friend bool operator==(                                                   \
        const distribution_type &dist1, const distribution_type &dist2)       \
    {                                                                         \
        return dist1.param() == dist2.param();                                \
    }                                                                         \
                                                                              \
    friend bool operator!=(                                                   \
        const distribution_type &dist1, const distribution_type &dist2)       \
    {                                                                         \
        return dist1.param() != dist2.param();                                \
    }                                                                         \
                                                                              \
    template <typename CharT, typename Traits>                                \
    friend std::basic_ostream<CharT, Traits> &operator<<(                     \
        std::basic_ostream<CharT, Traits> &os, const distribution_type &dist) \
    {                                                                         \
        os << dist.param();                                                   \
                                                                              \
        return os;                                                            \
    }                                                                         \
                                                                              \
    template <typename CharT, typename Traits>                                \
    friend std::basic_istream<CharT, Traits> &operator>>(                     \
        std::basic_istream<CharT, Traits> &is, distribution_type &dist)       \
    {                                                                         \
        param_type param;                                                     \
        is >> param;                                                          \
        if (is.good())                                                        \
            dist.param(std::move(param));                                     \
                                                                              \
        return is;                                                            \
    }

namespace vsmc
{

namespace internal
{

VSMC_DEFINE_TYPE_DISPATCH_TRAIT(KeyType, key_type, NullType)

template <typename RealType>
bool is_equal(RealType a, RealType b)
{
    if (a > b || a < b)
        return false;
    return true;
}

template <int N>
class RNGBitsNMax
{
    public:
    static constexpr std::uint64_t value = VSMC_MAX_UINT(std::uint64_t) >>
        (64 - N);
}; // class RNGBitsNMax

template <typename RNGType, int N>
class RNGBitsN
{
    static constexpr std::uint64_t umax = RNGType::max VSMC_MNE();
    static constexpr std::uint64_t bmax = RNGBitsNMax<N>::value;

    public:
    static constexpr int value =
        umax < bmax ? RNGBitsN<RNGType, N - 1>::value : N;
}; // class RNGBitsN

template <typename RNGType>
class RNGBitsN<RNGType, 0>
{
    public:
    static constexpr int value = 0;
}; // class RNGBitsN

template <typename RNGType>
class RNGBits : public RNGBitsN<RNGType, 64>
{
}; // class RNGBits

template <typename SeedSeq, typename U, typename V = U, typename W = V>
class is_seed_seq
    : public std::integral_constant<bool,
          !std::is_convertible<SeedSeq, U>::value &&
              !std::is_convertible<SeedSeq, V>::value &&
              !std::is_convertible<SeedSeq, W>::value &&
              !std::is_same<typename std::remove_cv<SeedSeq>::type,
                  U>::value &&
              !std::is_same<typename std::remove_cv<SeedSeq>::type,
                  V>::value &&
              !std::is_same<typename std::remove_cv<SeedSeq>::type, W>::value>
{
}; // class is_seed_seq

template <std::size_t, typename T, std::size_t K>
inline void increment_single(std::array<T, K> &ctr, std::false_type)
{
    ++ctr.back();
}

template <std::size_t N, typename T, std::size_t K>
inline void increment_single(std::array<T, K> &ctr, std::true_type)
{
    if (++std::get<N>(ctr) != 0)
        return;

    increment_single<N + 1>(ctr, std::integral_constant<bool, N + 2 < K>());
}

template <typename T, std::size_t K>
inline void increment(std::array<T, K> &, std::integral_constant<T, 0>)
{
}

template <typename T, std::size_t K, T NSkip>
inline void increment(std::array<T, K> &ctr, std::integral_constant<T, NSkip>)
{
    T old = ctr.front();
    ctr.front() += NSkip;
    if (ctr.front() > old)
        return;

    increment_single<1>(ctr, std::integral_constant<bool, 2 < K>());
}

template <typename T, std::size_t K>
inline void increment(std::array<T, K> &ctr, T nskip)
{
    T old = ctr.front();
    ctr.front() += nskip;
    if (ctr.front() > old || nskip == 0)
        return;

    increment_single<1>(ctr, std::integral_constant<bool, 2 < K>());
}

template <std::size_t Blocks, std::size_t, typename T, std::size_t K>
inline void increment_block(std::array<T, K> &,
    std::array<std::array<T, K>, Blocks> &, std::false_type)
{
}

template <std::size_t Blocks, std::size_t B, typename T, std::size_t K>
inline void increment_block(std::array<T, K> &ctr,
    std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
{
    std::get<B>(ctr_block) = ctr;
    increment(std::get<B>(ctr_block), std::integral_constant<T, B + 1>());
    increment_block<Blocks, B + 1>(
        ctr, ctr_block, std::integral_constant<bool, B + 2 < Blocks>());
}

template <std::size_t Blocks, std::size_t, typename T, std::size_t K>
inline void increment_block_safe(std::array<T, K> &,
    std::array<std::array<T, K>, Blocks> &, std::false_type)
{
}

template <std::size_t Blocks, std::size_t B, typename T, std::size_t K>
inline void increment_block_safe(std::array<T, K> &ctr,
    std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
{
    std::get<B>(ctr_block) = ctr;
    std::get<B>(ctr_block).front() += B + 1;
    increment_block_safe<Blocks, B + 1>(
        ctr, ctr_block, std::integral_constant<bool, B + 2 < Blocks>());
}

template <std::size_t Blocks, typename T, std::size_t K>
inline void increment_block_back(std::array<T, K> &ctr,
    std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
{
    ctr_block.back() = ctr;
    T old = ctr_block.back().front();
    ctr_block.back().front() += Blocks;
    if (ctr_block.back().front() > old) {
        increment_block_safe<Blocks, 0>(
            ctr, ctr_block, std::integral_constant<bool, 1 < Blocks>());
    } else {
        increment_single<1>(
            ctr_block.back(), std::integral_constant<bool, 2 < K>());
        increment_block<Blocks, 0>(
            ctr, ctr_block, std::integral_constant<bool, 1 < Blocks>());
    }
    ctr = ctr_block.back();
}

template <typename T, std::size_t K>
inline void increment(std::array<T, K> &ctr)
{
    increment_single<0>(ctr, std::integral_constant<bool, 1 < K>());
}

template <std::size_t Blocks, typename T, std::size_t K>
static void increment(
    std::array<T, K> &ctr, std::array<std::array<T, K>, Blocks> &ctr_block)
{
    increment_block_back<Blocks>(
        ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
}

} // namespace vsmc::internal

template <typename RNGType>
void rng_rand(RNGType &rng, std::size_t n, typename RNGType::result_type *r)
{
    for (std::size_t i = 0; i != n; ++i)
        r[i] = rng();
}

} // namespace vsmc

#endif // VSMC_RNG_INTERNAL_COMMON_HPP
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 Digital Bazaar, Inc.  All rights reserved.
 */
#include "db/io/File.h"
#include "db/io/FileList.h"

#include <sys/stat.h>
#include <dirent.h>

using namespace db::io;

File::File()
{
   mName = strdup("");
}

File::File(const char* name)
{
   mName = strdup(name);
}

File::~File()
{
   delete [] mName;
}

bool File::operator==(const File& rhs)
{
   bool rval = false;

   File* file = (File*)&rhs;

   // compare names and types for equality
   if(strcmp(mName, file->getName()) == 0)
   {
      if(isFile() == file->isFile() &&
         isDirectory() == file->isDirectory() &&
         isSymbolicLink() == file->isSymbolicLink())
      {
         rval = true;
      }
   }

   return rval;
}

bool File::exists()
{
   bool rval = false;

   struct stat s;
   int rc = stat(mName, &s);
   if(rc == 0)
   {
      rval = true;
   }
   else
   {
      // FIXME: add error handling
   }

   return rval;
}

bool File::remove()
{
   bool rval = false;

   int rc = ::remove(mName);
   if(rc == 0)
   {
      rval = true;
   }
   else
   {
      // FIXME: add error handling
   }

   return rval;
}

const char* File::getName() const
{
   return mName;
}

off_t File::getLength()
{
   struct stat s;
   int rc = stat(mName, &s);
   if(rc != 0)
   {
      // FIXME: add error handling
   }

   return s.st_size;
}

bool File::isFile()
{
   bool rval = false;

   // use lstat so symbolic links aren't followed
   struct stat s;
   int rc = lstat(mName, &s);
   if(rc != 0)
   {
      // FIXME: add error handling
   }
   else
   {
      // check for regular file
      rval = ((s.st_mode & S_IFMT) == S_IFREG);
   }

   return rval;
}

bool File::isDirectory()
{
   bool rval = false;

   // use lstat so symbolic links aren't followed
   struct stat s;
   int rc = lstat(mName, &s);
   if(rc != 0)
   {
      // FIXME: add error handling
   }
   else
   {
      // check for directory
      rval = ((s.st_mode & S_IFMT) == S_IFDIR);
   }

   return rval;
}

bool File::isSymbolicLink()
{
   bool rval = false;

   // use lstat so symbolic links aren't followed
   struct stat s;
   int rc = lstat(mName, &s);
   if(rc != 0)
   {
      // FIXME: add error handling
   }
   else
   {
      // check for symbolic link
      rval = ((s.st_mode & S_IFMT) == S_IFLNK);
   }

   return rval;
}

void File::listFiles(FileList* files)
{
   if(isDirectory())
   {
      // open directory
      DIR* dir = opendir(mName);
      if(dir == NULL)
      {
         // FIXME: add error handling
      }
      else
      {
         // read each directory entry
         struct dirent* entry;
         while((entry = readdir(dir)) != NULL)
         {
            // d_name is null-terminated name for file, add new File to list
            File* file = new File(entry->d_name);
            files->add(file);
         }

         // close directory
         closedir(dir);
      }
   }
}
<commit_msg>Added windows implementation for lstat().<commit_after>/*
 * Copyright (c) 2007 Digital Bazaar, Inc.  All rights reserved.
 */
#include "db/io/File.h"
#include "db/io/FileList.h"

#include <sys/stat.h>
#include <dirent.h>

#ifdef WIN32

// define file type for symbolic link
#define S_IFLNK   0xA000

/**
 * In windows, there are no symbolic links so lstat does the same
 * thing as stat(), namely, it gets information about a particular file.
 *
 * @param path the path to the file to stat.
 * @param buf the stat structure to populate.
 *
 * @return 0 if the stat was successful, -1 if not, with errno set.
 */
inline static int lstat(const char* path, struct stat* buf)
{
   return stat(path, buf);
}
#endif

using namespace db::io;

File::File()
{
   mName = strdup("");
}

File::File(const char* name)
{
   mName = strdup(name);
}

File::~File()
{
   delete [] mName;
}

bool File::operator==(const File& rhs)
{
   bool rval = false;

   File* file = (File*)&rhs;

   // compare names and types for equality
   if(strcmp(mName, file->getName()) == 0)
   {
      if(isFile() == file->isFile() &&
         isDirectory() == file->isDirectory() &&
         isSymbolicLink() == file->isSymbolicLink())
      {
         rval = true;
      }
   }

   return rval;
}

bool File::exists()
{
   bool rval = false;

   struct stat s;
   int rc = stat(mName, &s);
   if(rc == 0)
   {
      rval = true;
   }
   else
   {
      // FIXME: add error handling
   }

   return rval;
}

bool File::remove()
{
   bool rval = false;

   int rc = ::remove(mName);
   if(rc == 0)
   {
      rval = true;
   }
   else
   {
      // FIXME: add error handling
   }

   return rval;
}

const char* File::getName() const
{
   return mName;
}

off_t File::getLength()
{
   struct stat s;
   int rc = stat(mName, &s);
   if(rc != 0)
   {
      // FIXME: add error handling
   }

   return s.st_size;
}

bool File::isFile()
{
   bool rval = false;

   // use lstat so symbolic links aren't followed
   struct stat s;
   int rc = lstat(mName, &s);
   if(rc != 0)
   {
      // FIXME: add error handling
   }
   else
   {
      // check for regular file
      rval = ((s.st_mode & S_IFMT) == S_IFREG);
   }

   return rval;
}

bool File::isDirectory()
{
   bool rval = false;

   // use lstat so symbolic links aren't followed
   struct stat s;
   int rc = lstat(mName, &s);
   if(rc != 0)
   {
      // FIXME: add error handling
   }
   else
   {
      // check for directory
      rval = ((s.st_mode & S_IFMT) == S_IFDIR);
   }

   return rval;
}

bool File::isSymbolicLink()
{
   bool rval = false;

   // use lstat so symbolic links aren't followed
   struct stat s;
   int rc = lstat(mName, &s);
   if(rc != 0)
   {
      // FIXME: add error handling
   }
   else
   {
      // check for symbolic link
      rval = ((s.st_mode & S_IFMT) == S_IFLNK);
   }

   return rval;
}

void File::listFiles(FileList* files)
{
   if(isDirectory())
   {
      // open directory
      DIR* dir = opendir(mName);
      if(dir == NULL)
      {
         // FIXME: add error handling
      }
      else
      {
         // read each directory entry
         struct dirent* entry;
         while((entry = readdir(dir)) != NULL)
         {
            // d_name is null-terminated name for file, add new File to list
            File* file = new File(entry->d_name);
            files->add(file);
         }

         // close directory
         closedir(dir);
      }
   }
}
<|endoftext|>


<commit_before><commit_msg>Changed include paths.<commit_after><|endoftext|>


<commit_before>/*
 * smartmeter.hpp
 *
 *  Created on: Oct 17, 2013
 *      Author: seilbeck
 */

#ifndef SMARTMETER_HPP_
#define SMARTMETER_HPP_

#include "hidapi.h"

class SmartMeter {

public:
	struct Measurement {
		uint counter;
		double wattSum;
		double voltSum;
		double ampereSum;
	};

	/**
	 * interval - In which time intervals in ms is the energy consumption checked
	 */
	SmartMeter(uint interval);

	/**
	 * Initializes device.
	 * Returns false if no device could be found. True if initialization was successful.
	 *
	 */
	bool initDevice();

	void startMeasurement();

	/**
	 * Ends a measurement and returns a Measurement struct.
	 * This struct can be used to calculate the average energy consumption e.g. Measurment.wattSum / Measurement.counter
	 *
	 */
	Measurement endMeasurement();

	~SmartMeter(){
		if(device!=NULL)
			hid_close(device);
		if(measurement!=NULL)
			delete measurement;
		if(meter!=NULL)
			delete meter;
	};

private:
	Measurement* measurement;
	hid_device* device;
	std::thread* meter;
	bool measure;
	uint intervall;

	void performMeasurement();
};

#endif /* SMARTMETER_HPP_ */
<commit_msg>Added missing include<commit_after>/*
 * smartmeter.hpp
 *
 *  Created on: Oct 17, 2013
 *      Author: seilbeck
 */

#ifndef SMARTMETER_HPP_
#define SMARTMETER_HPP_

#include "hidapi.h"
#include <thread>

class SmartMeter {

public:
	struct Measurement {
		uint counter;
		double wattSum;
		double voltSum;
		double ampereSum;
	};

	/**
	 * interval - In which time intervals in ms is the energy consumption checked
	 */
	SmartMeter(uint interval);

	/**
	 * Initializes device.
	 * Returns false if no device could be found. True if initialization was successful.
	 *
	 */
	bool initDevice();

	void startMeasurement();

	/**
	 * Ends a measurement and returns a Measurement struct.
	 * This struct can be used to calculate the average energy consumption e.g. Measurment.wattSum / Measurement.counter
	 *
	 */
	Measurement endMeasurement();

	~SmartMeter(){
		if(device!=NULL)
			hid_close(device);
		if(measurement!=NULL)
			delete measurement;
		if(meter!=NULL)
			delete meter;
	};

private:
	Measurement* measurement;
	hid_device* device;
	std::thread* meter;
	bool measure;
	uint intervall;

	void performMeasurement();
};

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