<commit_before>#ifndef VEXCL_DEVLIST_HPP
#define VEXCL_DEVLIST_HPP

/*
The MIT License

Copyright (c) 2012-2014 Denis Demidov <dennis.demidov@gmail.com>

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   devlist.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  OpenCL device enumeration and context initialization.
 */

#include <vector>
#include <functional>
#include <string>
#include <cstdlib>

#include <vexcl/backend.hpp>
#include <vexcl/util.hpp>

#ifdef __GNUC__
#  ifndef _GLIBCXX_USE_NANOSLEEP
#    define _GLIBCXX_USE_NANOSLEEP
#  endif
#endif

namespace vex {

/// Device filters.
namespace Filter {
    /// \cond INTERNAL
    struct AnyFilter {
        bool operator()(const backend::device&) const {
            return true;
        }
    };
    /// \endcond

    /// Selects any device. \deprecated
    const AnyFilter All = {};

    /// Selects any device.
    const AnyFilter Any = {};

    /// Selects no more than given number of devices.
    /**
     * \note This filter should be the last in filter expression. In this case,
     * it will be applied only to devices which passed all other filters.
     * Otherwise, you could get less devices than planned (every time this
     * filter is applied, internal counter is decremented).
     */
    struct Count {
        explicit Count(int c) : count(c) {}

        bool operator()(const backend::device&) const {
            return --count >= 0;
        }

        private:
            mutable int count;
    };

    /// Selects one device at the given position.
    /**
     * Select one device at the given position in the list of devices
     * satisfying previously applied filters.
     */
    struct Position {
        explicit Position(int p) : pos(p) {}

        bool operator()(const backend::device&) const {
            return 0 == pos--;
        }

        private:
            mutable int pos;
    };

    /// \cond INTERNAL

    /// Negation of a filter.
    struct NegateFilter {
        template <class Filter>
        NegateFilter(Filter&& filter)
          : filter(std::forward<Filter>(filter)) {}

        bool operator()(const backend::device &d) const {
            return !filter(d);
        }

        private:
            std::function<bool(const backend::device&)> filter;
    };

    /// Filter join operators.
    enum FilterOp {
        FilterAnd, FilterOr
    };

    /// Filter join expression template.
    template <FilterOp op>
    struct FilterBinaryOp {
        template <class LHS, class RHS>
        FilterBinaryOp(LHS&& lhs, RHS&& rhs)
            : lhs(std::forward<LHS>(lhs)), rhs(std::forward<RHS>(rhs)) {}

        bool operator()(const backend::device &d) const {
            // This could be hidden into FilterOp::apply() call (with FilterOp
            // being a struct instead of enum), but this form allows to rely on
            // short-circuit evaluation (important for mutable filters as Count
            // or Position).
            switch (op) {
                case FilterOr:
                    return lhs(d) || rhs(d);
                case FilterAnd:
                default:
                    return lhs(d) && rhs(d);
            }
        }

        private:
            std::function<bool(const backend::device&)> lhs;
            std::function<bool(const backend::device&)> rhs;
    };

    /// \endcond

    /// Join two filters with AND operator.
    template <class LHS, class RHS>
    FilterBinaryOp<FilterAnd> operator&&(LHS&& lhs, RHS&& rhs)
    {
        return FilterBinaryOp<FilterAnd>(std::forward<LHS>(lhs), std::forward<RHS>(rhs));
    }

    /// Join two filters with OR operator.
    template <class LHS, class RHS>
    FilterBinaryOp<FilterOr> operator||(LHS&& lhs, RHS&& rhs)
    {
        return FilterBinaryOp<FilterOr>(std::forward<LHS>(lhs), std::forward<RHS>(rhs));
    }

    /// Negate a filter.
    template <class Filter>
    NegateFilter operator!(Filter&& filter) {
        return NegateFilter(std::forward<Filter>(filter));
    }

    /// Runtime filter holder.
    /**
     * The filter can be changed at runtime as in:
     \code
     vex::Filter::General f = vex::Filter::Env;
     if (need_double) f = f && vex::Filter::DoublePrecision;
     \endcode
     */
    struct General {
        template<class Filter>
        General(Filter filter) : filter(filter) { }

        bool operator()(const backend::device &d) const {
            return filter(d);
        }

        private:
            std::function<bool(const backend::device&)> filter;
    };

    /// \cond INTERNAL
    struct EnvFilter {
        EnvFilter()
            : filter( backend_env_filters() )
        {
#ifdef _MSC_VER
#  pragma warning(push)
#  pragma warning(disable: 4996)
#endif
            const char *maxdev   = getenv("OCL_MAX_DEVICES");
            const char *position = getenv("OCL_POSITION");
#ifdef _MSC_VER
#  pragma warning(pop)
#endif

            if (maxdev)   filter.push_back(Count(std::stoi(maxdev)));
            if (position) filter.push_back(Position(std::stoi(position)));
        }

        bool operator()(const backend::device &d) const {
            if (filter.empty()) return true;

            return std::all_of(
                    filter.begin(), filter.end(),
                    [d](const std::function<bool(const backend::device)> &f) {
                        return f(d);
                    });
        }

        private:
            std::vector< std::function<bool(const backend::device&)> > filter;
    };
    /// \endcond

    /// Environment filter
    /**
     * Selects devices with respect to environment variables. Recognized
     * variables are:
     *
     * \li OCL_PLATFORM -- platform name;
     * \li OCL_VENDOR   -- device vendor;
     * \li OCL_DEVICE   -- device name;
     * \li OCL_TYPE     -- device type (CPU, GPU, ACCELERATOR);
     * \li OCL_MAX_DEVICES -- maximum number of devices to use.
     * \li OCL_POSITION -- devices position in the device list.
     *
     * \note Since this filter possibly counts passed devices, it should be the
     * last in filter expression. Same reasoning applies as in case of
     * Filter::Count.
     */
    const EnvFilter Env;

} // namespace Filter

class Context;

template <bool dummy = true>
class StaticContext {
    static_assert(dummy, "dummy parameter should be true");

    public:
        static void set(Context &ctx) {
            instance = &ctx;
        }

        static const Context& get() {
            precondition(instance, "Uninitialized static context");
            return *instance;
        }
    private:
        static Context *instance;
};

template <bool dummy>
Context* StaticContext<dummy>::instance = 0;

/// Returns reference to the latest instance of vex::Context.
inline const Context& current_context() {
    return StaticContext<>::get();
}

/// Check if type is a device filter.
template <class T, class Enable = void>
struct is_device_filter : std::false_type {};

template <class T>
struct is_device_filter<T,
    typename std::enable_if<
            std::is_same<
                bool, typename std::result_of<T(const backend::device&)>::type
            >::value
        >::type
    > : std::true_type
{};

/// VexCL context holder.
/**
 * Holds vectors of backend::contexts and backend::command_queues returned by queue_list.
 */
class Context {
    public:
        /// Initialize context from a device filter.
        template <class F>
        explicit Context(F&& filter,
                backend::command_queue_properties properties = 0,
                typename std::enable_if<is_device_filter<F>::value>::type* = 0)
        {
            std::tie(c, q) = backend::queue_list(std::forward<F>(filter), properties);

#ifdef VEXCL_THROW_ON_EMPTY_CONTEXT
            precondition(!q.empty(), "No compute devices found");
#endif

            StaticContext<>::set(*this);
        }

        /// Initializes context from user-supplied list of backend::contexts and backend::command_queues.
        Context(const std::vector<std::pair<backend::context, backend::command_queue>> &user_ctx) {
            c.reserve(user_ctx.size());
            q.reserve(user_ctx.size());
            for(auto u = user_ctx.begin(); u != user_ctx.end(); u++) {
                c.push_back(u->first);
                q.push_back(u->second);
            }

            StaticContext<>::set(*this);
        }

        const std::vector<backend::context>& context() const {
            return c;
        }

        const backend::context& context(unsigned d) const {
            return c[d];
        }

        const std::vector<backend::command_queue>& queue() const {
            return q;
        }

        operator const std::vector<backend::command_queue>&() const {
            return q;
        }

        const backend::command_queue& queue(unsigned d) const {
            return q[d];
        }

        const backend::device device(unsigned d) const {
            return backend::device( backend::get_device_id(q[d]) );
        }

        size_t size() const {
            return q.size();
        }

        bool empty() const {
            return q.empty();
        }

        operator bool() const {
            return !empty();
        }

        void finish() const {
            for(auto queue = q.begin(); queue != q.end(); ++queue)
                queue->finish();
        }
    private:
        std::vector<backend::context>       c;
        std::vector<backend::command_queue> q;
};

} // namespace vex

namespace std {

/// Output list of devices to stream.
inline std::ostream& operator<<(std::ostream &os,
        const std::vector<vex::backend::command_queue> &queue)
{
    unsigned p = 0;

    for(auto q = queue.begin(); q != queue.end(); q++)
        os << ++p << ". " << *q << std::endl;

    return os;
}

/// Output list of devices to stream.
inline std::ostream& operator<<(std::ostream &os, const vex::Context &ctx) {
    return os << ctx.queue();
}

}

#endif
<commit_msg>Provide alternative Context constructor for user-supplied contexts/queues<commit_after>#ifndef VEXCL_DEVLIST_HPP
#define VEXCL_DEVLIST_HPP

/*
The MIT License

Copyright (c) 2012-2014 Denis Demidov <dennis.demidov@gmail.com>

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   devlist.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  OpenCL device enumeration and context initialization.
 */

#include <vector>
#include <functional>
#include <string>
#include <cstdlib>

#include <vexcl/backend.hpp>
#include <vexcl/util.hpp>

#ifdef __GNUC__
#  ifndef _GLIBCXX_USE_NANOSLEEP
#    define _GLIBCXX_USE_NANOSLEEP
#  endif
#endif

namespace vex {

/// Device filters.
namespace Filter {
    /// \cond INTERNAL
    struct AnyFilter {
        bool operator()(const backend::device&) const {
            return true;
        }
    };
    /// \endcond

    /// Selects any device. \deprecated
    const AnyFilter All = {};

    /// Selects any device.
    const AnyFilter Any = {};

    /// Selects no more than given number of devices.
    /**
     * \note This filter should be the last in filter expression. In this case,
     * it will be applied only to devices which passed all other filters.
     * Otherwise, you could get less devices than planned (every time this
     * filter is applied, internal counter is decremented).
     */
    struct Count {
        explicit Count(int c) : count(c) {}

        bool operator()(const backend::device&) const {
            return --count >= 0;
        }

        private:
            mutable int count;
    };

    /// Selects one device at the given position.
    /**
     * Select one device at the given position in the list of devices
     * satisfying previously applied filters.
     */
    struct Position {
        explicit Position(int p) : pos(p) {}

        bool operator()(const backend::device&) const {
            return 0 == pos--;
        }

        private:
            mutable int pos;
    };

    /// \cond INTERNAL

    /// Negation of a filter.
    struct NegateFilter {
        template <class Filter>
        NegateFilter(Filter&& filter)
          : filter(std::forward<Filter>(filter)) {}

        bool operator()(const backend::device &d) const {
            return !filter(d);
        }

        private:
            std::function<bool(const backend::device&)> filter;
    };

    /// Filter join operators.
    enum FilterOp {
        FilterAnd, FilterOr
    };

    /// Filter join expression template.
    template <FilterOp op>
    struct FilterBinaryOp {
        template <class LHS, class RHS>
        FilterBinaryOp(LHS&& lhs, RHS&& rhs)
            : lhs(std::forward<LHS>(lhs)), rhs(std::forward<RHS>(rhs)) {}

        bool operator()(const backend::device &d) const {
            // This could be hidden into FilterOp::apply() call (with FilterOp
            // being a struct instead of enum), but this form allows to rely on
            // short-circuit evaluation (important for mutable filters as Count
            // or Position).
            switch (op) {
                case FilterOr:
                    return lhs(d) || rhs(d);
                case FilterAnd:
                default:
                    return lhs(d) && rhs(d);
            }
        }

        private:
            std::function<bool(const backend::device&)> lhs;
            std::function<bool(const backend::device&)> rhs;
    };

    /// \endcond

    /// Join two filters with AND operator.
    template <class LHS, class RHS>
    FilterBinaryOp<FilterAnd> operator&&(LHS&& lhs, RHS&& rhs)
    {
        return FilterBinaryOp<FilterAnd>(std::forward<LHS>(lhs), std::forward<RHS>(rhs));
    }

    /// Join two filters with OR operator.
    template <class LHS, class RHS>
    FilterBinaryOp<FilterOr> operator||(LHS&& lhs, RHS&& rhs)
    {
        return FilterBinaryOp<FilterOr>(std::forward<LHS>(lhs), std::forward<RHS>(rhs));
    }

    /// Negate a filter.
    template <class Filter>
    NegateFilter operator!(Filter&& filter) {
        return NegateFilter(std::forward<Filter>(filter));
    }

    /// Runtime filter holder.
    /**
     * The filter can be changed at runtime as in:
     \code
     vex::Filter::General f = vex::Filter::Env;
     if (need_double) f = f && vex::Filter::DoublePrecision;
     \endcode
     */
    struct General {
        template<class Filter>
        General(Filter filter) : filter(filter) { }

        bool operator()(const backend::device &d) const {
            return filter(d);
        }

        private:
            std::function<bool(const backend::device&)> filter;
    };

    /// \cond INTERNAL
    struct EnvFilter {
        EnvFilter()
            : filter( backend_env_filters() )
        {
#ifdef _MSC_VER
#  pragma warning(push)
#  pragma warning(disable: 4996)
#endif
            const char *maxdev   = getenv("OCL_MAX_DEVICES");
            const char *position = getenv("OCL_POSITION");
#ifdef _MSC_VER
#  pragma warning(pop)
#endif

            if (maxdev)   filter.push_back(Count(std::stoi(maxdev)));
            if (position) filter.push_back(Position(std::stoi(position)));
        }

        bool operator()(const backend::device &d) const {
            if (filter.empty()) return true;

            return std::all_of(
                    filter.begin(), filter.end(),
                    [d](const std::function<bool(const backend::device)> &f) {
                        return f(d);
                    });
        }

        private:
            std::vector< std::function<bool(const backend::device&)> > filter;
    };
    /// \endcond

    /// Environment filter
    /**
     * Selects devices with respect to environment variables. Recognized
     * variables are:
     *
     * \li OCL_PLATFORM -- platform name;
     * \li OCL_VENDOR   -- device vendor;
     * \li OCL_DEVICE   -- device name;
     * \li OCL_TYPE     -- device type (CPU, GPU, ACCELERATOR);
     * \li OCL_MAX_DEVICES -- maximum number of devices to use.
     * \li OCL_POSITION -- devices position in the device list.
     *
     * \note Since this filter possibly counts passed devices, it should be the
     * last in filter expression. Same reasoning applies as in case of
     * Filter::Count.
     */
    const EnvFilter Env;

} // namespace Filter

class Context;

template <bool dummy = true>
class StaticContext {
    static_assert(dummy, "dummy parameter should be true");

    public:
        static void set(Context &ctx) {
            instance = &ctx;
        }

        static const Context& get() {
            precondition(instance, "Uninitialized static context");
            return *instance;
        }
    private:
        static Context *instance;
};

template <bool dummy>
Context* StaticContext<dummy>::instance = 0;

/// Returns reference to the latest instance of vex::Context.
inline const Context& current_context() {
    return StaticContext<>::get();
}

/// Check if type is a device filter.
template <class T, class Enable = void>
struct is_device_filter : std::false_type {};

template <class T>
struct is_device_filter<T,
    typename std::enable_if<
            std::is_same<
                bool, typename std::result_of<T(const backend::device&)>::type
            >::value
        >::type
    > : std::true_type
{};

/// VexCL context holder.
/**
 * Holds vectors of backend::contexts and backend::command_queues returned by queue_list.
 */
class Context {
    public:
        /// Initialize context from a device filter.
        template <class F>
        explicit Context(F&& filter,
                backend::command_queue_properties properties = 0,
                typename std::enable_if<is_device_filter<F>::value>::type* = 0)
        {
            std::tie(c, q) = backend::queue_list(std::forward<F>(filter), properties);

#ifdef VEXCL_THROW_ON_EMPTY_CONTEXT
            precondition(!q.empty(), "No compute devices found");
#endif

            StaticContext<>::set(*this);
        }

        /// Initializes context from user-supplied list of backend::contexts and backend::command_queues.
        Context(const std::vector<std::pair<backend::context, backend::command_queue>> &user_ctx) {
            c.reserve(user_ctx.size());
            q.reserve(user_ctx.size());
            for(auto u = user_ctx.begin(); u != user_ctx.end(); u++) {
                c.push_back(u->first);
                q.push_back(u->second);
            }

            StaticContext<>::set(*this);
        }

        /// Initializes context from user-supplied list of backend::contexts and backend::command_queues.
        Context(std::vector<backend::context> c, std::vector<backend::command_queue> q)
            : c(std::move(c)), q(std::move(q))
        {
            StaticContext<>::set(*this);
        }

        const std::vector<backend::context>& context() const {
            return c;
        }

        const backend::context& context(unsigned d) const {
            return c[d];
        }

        const std::vector<backend::command_queue>& queue() const {
            return q;
        }

        operator const std::vector<backend::command_queue>&() const {
            return q;
        }

        const backend::command_queue& queue(unsigned d) const {
            return q[d];
        }

        const backend::device device(unsigned d) const {
            return backend::device( backend::get_device_id(q[d]) );
        }

        size_t size() const {
            return q.size();
        }

        bool empty() const {
            return q.empty();
        }

        operator bool() const {
            return !empty();
        }

        void finish() const {
            for(auto queue = q.begin(); queue != q.end(); ++queue)
                queue->finish();
        }
    private:
        std::vector<backend::context>       c;
        std::vector<backend::command_queue> q;
};

} // namespace vex

namespace std {

/// Output list of devices to stream.
inline std::ostream& operator<<(std::ostream &os,
        const std::vector<vex::backend::command_queue> &queue)
{
    unsigned p = 0;

    for(auto q = queue.begin(); q != queue.end(); q++)
        os << ++p << ". " << *q << std::endl;

    return os;
}

/// Output list of devices to stream.
inline std::ostream& operator<<(std::ostream &os, const vex::Context &ctx) {
    return os << ctx.queue();
}

}

#endif
<|endoftext|>


<commit_before>///
/// @file  LoadBalancer.cpp
/// @brief The LoadBalancer assigns work to the individual threads
///        in the computation of the special leaves in the
///        Lagarias-Miller-Odlyzko and Deleglise-Rivat prime
///        counting algorithms.
///
///        Simply parallelizing the computation of the special
///        leaves in the Lagarias-Miller-Odlyzko algorithm by
///        subdividing the sieve interval by the number of threads
///        into equally sized subintervals does not scale because
///        the distribution of the special leaves is highly skewed
///        and most special leaves are in the first few segments
///        whereas later on there are very few special leaves.
///
///        This LoadBalancer gradually increases the number of
///        segments to sieve as long the expected runtime of the
///        sieve distance is smaller than the expected finish time
///        of the algorithm. Near the end the LoadBalancer will
///        gradually decrease the number of segments to sieve in
///        order to prevent that 1 thread will run much longer
///        than all the other threads.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <LoadBalancer.hpp>
#include <primecount-internal.hpp>
#include <S2Status.hpp>
#include <Sieve.hpp>
#include <imath.hpp>
#include <int128_t.hpp>
#include <min.hpp>
#include <calculator.hpp>
#include <json.hpp>

#include <stdint.h>
#include <cmath>
#include <string>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;

namespace primecount {

template <typename T>
void print_resume(double percent, T x)
{
  print_log("Resume from " + backup_file());
  print_status(percent, x);
}

int LoadBalancer::resume_threads() const
{
  int threads = 0;

  if (is_resume(copy_, "S2_hard", x_, y_, z_))
  {
    int threads = copy_["S2_hard"]["threads"];
    double percent = json_["S2_hard"]["percent"];
    print_resume(percent, x_);
  }

  return threads;
}

/// backup thread
void LoadBalancer::backup(int threads,
                          int thread_id,
                          int64_t low,
                          int64_t segments,
                          int64_t segment_size)
{
  double percent = status_.getPercent(low_, z_, s2_total_, s2_approx_);
  double seconds = get_wtime() - backup_time_;

  string tid = "thread" + to_string(thread_id);

  json_["S2_hard"]["threads"] = threads;
  json_["S2_hard"]["low"] = low_;
  json_["S2_hard"]["segments"] = segments_;
  json_["S2_hard"]["segment_size"] = segment_size_;
  json_["S2_hard"]["s2_hard"] = to_string(s2_total_);
  json_["S2_hard"]["percent"] = percent;
  json_["S2_hard"]["seconds"] = get_wtime() - time_;
  json_["S2_hard"][tid]["low"] = low;
  json_["S2_hard"][tid]["segments"] = segments;
  json_["S2_hard"][tid]["segment_size"] = segment_size;

  if (seconds > 60)
  {
    backup_time_ = get_wtime();
    store_backup(json_);
  }
}

/// backup result
void LoadBalancer::backup()
{
  json_.erase("S2_hard");

  json_["S2_hard"]["x"] = to_string(x_);
  json_["S2_hard"]["y"] = y_;
  json_["S2_hard"]["z"] = z_;
  json_["S2_hard"]["s2_hard"] = to_string(s2_total_);
  json_["S2_hard"]["percent"] = 100;
  json_["S2_hard"]["seconds"] = get_wtime() - time_;

  store_backup(json_);
}

/// resume thread
bool LoadBalancer::resume(int thread_id,
                          int64_t& low,
                          int64_t& segments,
                          int64_t& segment_size)
{
  bool resumed = false;

  #pragma omp critical (LoadBalancer)
  if (is_resume(copy_, "S2_hard", thread_id, x_, y_, z_))
  {
    string tid = "thread" + to_string(thread_id);
    low = copy_["S2_hard"][tid]["low"];
    segments = copy_["S2_hard"][tid]["segments"];
    segment_size = copy_["S2_hard"][tid]["segment_size"];
    resumed = true;
  }

  return resumed;
}

// resume result
bool LoadBalancer::resume(maxint_t& s2_hard, double& time) const
{
  if (is_resume(copy_, "S2_hard", x_, y_, z_) &&
      copy_["S2_hard"].count("low") == 0)
  {
    double percent = copy_["S2_hard"]["percent"];
    double seconds = copy_["S2_hard"]["seconds"];

    s2_hard = calculator::eval<maxint_t>(copy_["S2_hard"]["s2_hard"]);
    time = get_wtime() - seconds;
    print_resume(percent, x_);
    return true;
  }

  return false;
}

LoadBalancer::LoadBalancer(maxint_t x,
                           int64_t y,
                           int64_t z,
                           maxint_t s2_approx) :
  low_(0),
  max_low_(0),
  x_(x),
  y_(y),
  z_(z),
  segments_(1),
  s2_total_(0),
  s2_approx_(s2_approx),
  time_(get_wtime()),
  backup_time_(get_wtime()),
  status_(x),
  json_(load_backup())
{
  // Read only json copy that is accessed
  // in parallel by multiple threads
  copy_ = json_;

  if (is_resume(json_, "S2_hard", x_, y_, z_))
  {
    double seconds = copy_["S2_hard"]["seconds"];
    s2_total_ = calculator::eval<maxint_t>(copy_["S2_hard"]["s2_hard"]);
    time_ = get_wtime() - seconds;

    if (json_["S2_hard"].count("low"))
    {
      low_ = copy_["S2_hard"]["low"];
      segments_ = copy_["S2_hard"]["segments"];
      segment_size_ = copy_["S2_hard"]["segment_size"];
    }
  }
  else
  {
    json_.erase("S2_hard");
    json_["S2_hard"]["x"] = to_string(x_);
    json_["S2_hard"]["y"] = y_;
    json_["S2_hard"]["z"] = z_;
  }

  init_size();
  maxint_t x16 = iroot<6>(x);
  double alpha = get_alpha(x, y);
  smallest_hard_leaf_ = (int64_t) (x / (y * sqrt(alpha) * x16));
}

void LoadBalancer::init_size()
{
  // start with a tiny segment_size as most
  // special leaves are in the first few segments
  // and we need to ensure that all threads are
  // assigned an equal amount of work
  int64_t sqrtz = isqrt(z_);
  int64_t log = ilog(sqrtz);
  log = max(log, 1);
  segment_size_ = sqrtz / log;

  int64_t min_size = 1 << 9;
  segment_size_ = max(segment_size_, min_size);
  segment_size_ = Sieve::get_segment_size(segment_size_);

  // try to use a segment size that fits exactly
  // into the CPUs L1 data cache
  int64_t l1_dcache_size = 1 << 15;
  max_size_ = l1_dcache_size * 30;
  max_size_ = max(max_size_, sqrtz);
  max_size_ = Sieve::get_segment_size(max_size_);
}

maxint_t LoadBalancer::get_result() const
{
  return s2_total_;
}

double LoadBalancer::get_time() const
{
  return time_;
}

bool LoadBalancer::get_work(int threads,
                            int thread_id,
                            int64_t* low,
                            int64_t* segments,
                            int64_t* segment_size,
                            maxint_t s2,
                            Runtime& runtime)
{
  #pragma omp critical (LoadBalancer)
  {
    s2_total_ += s2;

    update(low, segments, runtime);

    *low = low_;
    *segments = segments_;
    *segment_size = segment_size_;

    low_ += segments_ * segment_size_;

    backup(threads, thread_id, *low, *segments, *segment_size);

    if (is_print())
      status_.print(s2_total_, s2_approx_);
  }

  return *low <= z_;
}

void LoadBalancer::update(int64_t* low,
                          int64_t* segments,
                          Runtime& runtime)
{
  if (*low > max_low_)
  {
    max_low_ = *low;
    segments_ = *segments;

    if (segment_size_ < max_size_)
      segment_size_ = min(segment_size_ * 2, max_size_);
    else
    {
      double next = get_next(runtime);
      next = in_between(0.25, next, 2.0);
      next *= segments_;
      next = max(1.0, next);
      segments_ = (int64_t) next;
    }
  }

  auto high = low_ + segments_ * segment_size_;

  // Most hard special leaves are located just past
  // smallest_hard_leaf_. In order to prevent assigning
  // the bulk of work to a single thread we reduce
  // the number of segments to a minimum.
  //
  if (smallest_hard_leaf_ >= low_ &&
      smallest_hard_leaf_ <= high)
  {
    segments_ = 1;
  }
}

double LoadBalancer::get_next(Runtime& runtime) const
{
  double min_secs = runtime.init * 10;
  double run_secs = runtime.secs;

  min_secs = max(min_secs, 0.01);
  run_secs = max(run_secs, min_secs / 10);

  double rem = remaining_secs();
  double threshold = rem / 4;
  threshold = max(threshold, min_secs);

  return threshold / run_secs;
}

/// Remaining seconds till finished
double LoadBalancer::remaining_secs() const
{
  double percent = status_.getPercent(low_, z_, s2_total_, s2_approx_);
  percent = in_between(20, percent, 100);

  double total_secs = get_wtime() - time_;
  double secs = total_secs * (100 / percent) - total_secs;
  return secs;
}

} // namespace
<commit_msg>Remove critical section<commit_after>///
/// @file  LoadBalancer.cpp
/// @brief The LoadBalancer assigns work to the individual threads
///        in the computation of the special leaves in the
///        Lagarias-Miller-Odlyzko and Deleglise-Rivat prime
///        counting algorithms.
///
///        Simply parallelizing the computation of the special
///        leaves in the Lagarias-Miller-Odlyzko algorithm by
///        subdividing the sieve interval by the number of threads
///        into equally sized subintervals does not scale because
///        the distribution of the special leaves is highly skewed
///        and most special leaves are in the first few segments
///        whereas later on there are very few special leaves.
///
///        This LoadBalancer gradually increases the number of
///        segments to sieve as long the expected runtime of the
///        sieve distance is smaller than the expected finish time
///        of the algorithm. Near the end the LoadBalancer will
///        gradually decrease the number of segments to sieve in
///        order to prevent that 1 thread will run much longer
///        than all the other threads.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <LoadBalancer.hpp>
#include <primecount-internal.hpp>
#include <S2Status.hpp>
#include <Sieve.hpp>
#include <imath.hpp>
#include <int128_t.hpp>
#include <min.hpp>
#include <calculator.hpp>
#include <json.hpp>

#include <stdint.h>
#include <cmath>
#include <string>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;

namespace primecount {

template <typename T>
void print_resume(double percent, T x)
{
  print_log("Resume from " + backup_file());
  print_status(percent, x);
}

int LoadBalancer::resume_threads() const
{
  int threads = 0;

  if (is_resume(copy_, "S2_hard", x_, y_, z_))
  {
    int threads = copy_["S2_hard"]["threads"];
    double percent = json_["S2_hard"]["percent"];
    print_resume(percent, x_);
  }

  return threads;
}

/// backup thread
void LoadBalancer::backup(int threads,
                          int thread_id,
                          int64_t low,
                          int64_t segments,
                          int64_t segment_size)
{
  double percent = status_.getPercent(low_, z_, s2_total_, s2_approx_);
  double seconds = get_wtime() - backup_time_;

  string tid = "thread" + to_string(thread_id);

  json_["S2_hard"]["threads"] = threads;
  json_["S2_hard"]["low"] = low_;
  json_["S2_hard"]["segments"] = segments_;
  json_["S2_hard"]["segment_size"] = segment_size_;
  json_["S2_hard"]["s2_hard"] = to_string(s2_total_);
  json_["S2_hard"]["percent"] = percent;
  json_["S2_hard"]["seconds"] = get_wtime() - time_;
  json_["S2_hard"][tid]["low"] = low;
  json_["S2_hard"][tid]["segments"] = segments;
  json_["S2_hard"][tid]["segment_size"] = segment_size;

  if (seconds > 60)
  {
    backup_time_ = get_wtime();
    store_backup(json_);
  }
}

/// backup result
void LoadBalancer::backup()
{
  json_.erase("S2_hard");

  json_["S2_hard"]["x"] = to_string(x_);
  json_["S2_hard"]["y"] = y_;
  json_["S2_hard"]["z"] = z_;
  json_["S2_hard"]["s2_hard"] = to_string(s2_total_);
  json_["S2_hard"]["percent"] = 100;
  json_["S2_hard"]["seconds"] = get_wtime() - time_;

  store_backup(json_);
}

/// resume thread
bool LoadBalancer::resume(int thread_id,
                          int64_t& low,
                          int64_t& segments,
                          int64_t& segment_size)
{
  if (is_resume(copy_, "S2_hard", thread_id, x_, y_, z_))
  {
    string tid = "thread" + to_string(thread_id);
    low = copy_["S2_hard"][tid]["low"];
    segments = copy_["S2_hard"][tid]["segments"];
    segment_size = copy_["S2_hard"][tid]["segment_size"];
    return true;
  }

  return false;
}

// resume result
bool LoadBalancer::resume(maxint_t& s2_hard, double& time) const
{
  if (is_resume(copy_, "S2_hard", x_, y_, z_) &&
      copy_["S2_hard"].count("low") == 0)
  {
    double percent = copy_["S2_hard"]["percent"];
    double seconds = copy_["S2_hard"]["seconds"];

    s2_hard = calculator::eval<maxint_t>(copy_["S2_hard"]["s2_hard"]);
    time = get_wtime() - seconds;
    print_resume(percent, x_);
    return true;
  }

  return false;
}

LoadBalancer::LoadBalancer(maxint_t x,
                           int64_t y,
                           int64_t z,
                           maxint_t s2_approx) :
  low_(0),
  max_low_(0),
  x_(x),
  y_(y),
  z_(z),
  segments_(1),
  s2_total_(0),
  s2_approx_(s2_approx),
  time_(get_wtime()),
  backup_time_(get_wtime()),
  status_(x),
  json_(load_backup())
{
  // Read only json copy that is accessed
  // in parallel by multiple threads
  copy_ = json_;

  if (is_resume(json_, "S2_hard", x_, y_, z_))
  {
    double seconds = copy_["S2_hard"]["seconds"];
    s2_total_ = calculator::eval<maxint_t>(copy_["S2_hard"]["s2_hard"]);
    time_ = get_wtime() - seconds;

    if (json_["S2_hard"].count("low"))
    {
      low_ = copy_["S2_hard"]["low"];
      segments_ = copy_["S2_hard"]["segments"];
      segment_size_ = copy_["S2_hard"]["segment_size"];
    }
  }
  else
  {
    json_.erase("S2_hard");
    json_["S2_hard"]["x"] = to_string(x_);
    json_["S2_hard"]["y"] = y_;
    json_["S2_hard"]["z"] = z_;
  }

  init_size();
  maxint_t x16 = iroot<6>(x);
  double alpha = get_alpha(x, y);
  smallest_hard_leaf_ = (int64_t) (x / (y * sqrt(alpha) * x16));
}

void LoadBalancer::init_size()
{
  // start with a tiny segment_size as most
  // special leaves are in the first few segments
  // and we need to ensure that all threads are
  // assigned an equal amount of work
  int64_t sqrtz = isqrt(z_);
  int64_t log = ilog(sqrtz);
  log = max(log, 1);
  segment_size_ = sqrtz / log;

  int64_t min_size = 1 << 9;
  segment_size_ = max(segment_size_, min_size);
  segment_size_ = Sieve::get_segment_size(segment_size_);

  // try to use a segment size that fits exactly
  // into the CPUs L1 data cache
  int64_t l1_dcache_size = 1 << 15;
  max_size_ = l1_dcache_size * 30;
  max_size_ = max(max_size_, sqrtz);
  max_size_ = Sieve::get_segment_size(max_size_);
}

maxint_t LoadBalancer::get_result() const
{
  return s2_total_;
}

double LoadBalancer::get_time() const
{
  return time_;
}

bool LoadBalancer::get_work(int threads,
                            int thread_id,
                            int64_t* low,
                            int64_t* segments,
                            int64_t* segment_size,
                            maxint_t s2,
                            Runtime& runtime)
{
  #pragma omp critical (LoadBalancer)
  {
    s2_total_ += s2;

    update(low, segments, runtime);

    *low = low_;
    *segments = segments_;
    *segment_size = segment_size_;

    low_ += segments_ * segment_size_;

    backup(threads, thread_id, *low, *segments, *segment_size);

    if (is_print())
      status_.print(s2_total_, s2_approx_);
  }

  return *low <= z_;
}

void LoadBalancer::update(int64_t* low,
                          int64_t* segments,
                          Runtime& runtime)
{
  if (*low > max_low_)
  {
    max_low_ = *low;
    segments_ = *segments;

    if (segment_size_ < max_size_)
      segment_size_ = min(segment_size_ * 2, max_size_);
    else
    {
      double next = get_next(runtime);
      next = in_between(0.25, next, 2.0);
      next *= segments_;
      next = max(1.0, next);
      segments_ = (int64_t) next;
    }
  }

  auto high = low_ + segments_ * segment_size_;

  // Most hard special leaves are located just past
  // smallest_hard_leaf_. In order to prevent assigning
  // the bulk of work to a single thread we reduce
  // the number of segments to a minimum.
  //
  if (smallest_hard_leaf_ >= low_ &&
      smallest_hard_leaf_ <= high)
  {
    segments_ = 1;
  }
}

double LoadBalancer::get_next(Runtime& runtime) const
{
  double min_secs = runtime.init * 10;
  double run_secs = runtime.secs;

  min_secs = max(min_secs, 0.01);
  run_secs = max(run_secs, min_secs / 10);

  double rem = remaining_secs();
  double threshold = rem / 4;
  threshold = max(threshold, min_secs);

  return threshold / run_secs;
}

/// Remaining seconds till finished
double LoadBalancer::remaining_secs() const
{
  double percent = status_.getPercent(low_, z_, s2_total_, s2_approx_);
  percent = in_between(20, percent, 100);

  double total_secs = get_wtime() - time_;
  double secs = total_secs * (100 / percent) - total_secs;
  return secs;
}

} // namespace
<|endoftext|>


<commit_before>/*=============================================================================

  MYPROJECT: A software package for whatever.

  Copyright (c) University College London (UCL). All rights reserved.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

  See LICENSE.txt in the top level directory for details.

=============================================================================*/

#include "mpQQuickVTKView.h"
#include <vtkRendererCollection.h>
#include <vtkEventQtSlotConnect.h>
#include <QVTKInteractorAdapter.h>
#include <QMutexLocker>

namespace mp {

//-----------------------------------------------------------------------------
QQuickVTKView::~QQuickVTKView()
{
  if (m_VTKRenderWindow)
  {
    m_VTKRenderWindowInteractor->Disable();
    m_VTKRenderWindow->SetInteractor(nullptr);
#ifdef BUILD_VTK_OpenGL2
    m_VTKRenderWindow->SetReadyForRendering(false);
#endif
    m_VTKRenderWindow->RemoveAllObservers();
    vtkRendererCollection *c = m_VTKRenderWindow->GetRenderers();
    vtkRenderer *v = nullptr;
    while(v = c->GetNextItem(), v != nullptr)
    {
      m_VTKRenderWindow->RemoveRenderer(v);
    }
  }
}

//-----------------------------------------------------------------------------
QQuickVTKView::QQuickVTKView(QWindow * parent)
: QQuickView(parent)
, m_Mutex(QMutex::NonRecursive)
, m_VTKRenderWindow(nullptr)
, m_VTKRenderWindowInteractor(nullptr)
, m_VTKInteractorStyleMultiTouchCamera(nullptr)
, m_EraseBeforeVTKRendering(true)
{
  this->Init();
}

//-----------------------------------------------------------------------------
QQuickVTKView::QQuickVTKView(QQmlEngine * engine, QWindow * parent)
: QQuickView(engine, parent)
, m_Mutex(QMutex::NonRecursive)
, m_VTKRenderWindow(nullptr)
, m_VTKRenderWindowInteractor(nullptr)
, m_VTKInteractorStyleMultiTouchCamera(nullptr)
, m_EraseBeforeVTKRendering(true)
{
  this->Init();
}

//-----------------------------------------------------------------------------
QQuickVTKView::QQuickVTKView(const QUrl & source, QWindow * parent)
: QQuickView(source, parent)
, m_Mutex(QMutex::NonRecursive)
, m_VTKRenderWindow(nullptr)
, m_VTKRenderWindowInteractor(nullptr)
, m_VTKInteractorStyleMultiTouchCamera(nullptr)
, m_EraseBeforeVTKRendering(true)
{
  this->Init();
}

//-----------------------------------------------------------------------------
void QQuickVTKView::Init()
{
  m_VTKRenderWindow = vtkExternalOpenGLRenderWindow::New();

  m_VTKInteractorStyleMultiTouchCamera = vtkInteractorStyleMultiTouchCamera::New();

  m_VTKRenderWindowInteractor = vtkRenderWindowInteractor::New();
  m_VTKRenderWindowInteractor->SetRenderWindow(m_VTKRenderWindow);
  m_VTKRenderWindowInteractor->SetInteractorStyle(m_VTKInteractorStyleMultiTouchCamera);
  m_VTKRenderWindowInteractor->SetEnableRender(false); // this is to stop interactor triggering Render().

  m_VTKInteractorAdapter = new QVTKInteractorAdapter(this);
  m_VTKInteractorAdapter->SetDevicePixelRatio(this->devicePixelRatio());

  m_EventSlotConnector = vtkSmartPointer<vtkEventQtSlotConnect>::New();

  connect(this, SIGNAL(beforeRendering()), this, SLOT(Render()), Qt::DirectConnection);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::AddRenderer(vtkRenderer* r)
{
  m_VTKRenderWindow->AddRenderer(r);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::RemoveRenderer(vtkRenderer *r)
{
  m_VTKRenderWindow->RemoveRenderer(r);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::SetEraseBeforeVTKRendering(bool b)
{
  m_EraseBeforeVTKRendering = b;
  m_VTKRenderWindow->SetErase(m_EraseBeforeVTKRendering);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::Render()
{
  emit beforeVTKRendering();

  QMutexLocker lock(&m_Mutex);

  m_VTKRenderWindow->Render();
  emit afterVTKRendering();
}

//-----------------------------------------------------------------------------
void QQuickVTKView::SetEnabled(bool isEnabled)
{
  if (isEnabled)
  {
    m_VTKRenderWindowInteractor->Enable();
  }
  else
  {
    m_VTKRenderWindowInteractor->Disable();
  }
}

//-----------------------------------------------------------------------------
bool QQuickVTKView::event(QEvent *e)
{
  if(e->type() == QEvent::TouchBegin ||
     e->type() == QEvent::TouchUpdate ||
     e->type() == QEvent::TouchEnd
    )
  {
    QMutexLocker lock(&m_Mutex);
    if(m_VTKRenderWindow
#ifdef BUILD_VTK_OpenGL2
      && m_VTKRenderWindow->GetReadyForRendering()
#endif
      )
    {
      m_VTKInteractorAdapter->ProcessEvent(e, m_VTKRenderWindow->GetInteractor());
      if (e->isAccepted())
      {
        return true;
      }
    }
  }
  return QQuickView::event(e);
}

//-----------------------------------------------------------------------------
bool QQuickVTKView::ProcessEvent(QEvent* e)
{
  QMutexLocker lock(&m_Mutex);
  if (m_VTKRenderWindow
#ifdef BUILD_VTK_OpenGL2
    && m_VTKRenderWindow->GetReadyForRendering()
#endif
    )
  {
    return m_VTKInteractorAdapter->ProcessEvent(e, m_VTKRenderWindowInteractor);
  }
  return false;
}

//-----------------------------------------------------------------------------
void QQuickVTKView::mousePressEvent(QMouseEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::mouseMoveEvent(QMouseEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::mouseReleaseEvent(QMouseEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::mouseDoubleClickEvent(QMouseEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::keyPressEvent(QKeyEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::keyReleaseEvent(QKeyEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::enterEvent(QEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::leaveEvent(QEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::wheelEvent(QWheelEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
} // end namespace
<commit_msg>Issue #39: Update comment, VTK interaction working on Windows, Mac.<commit_after>/*=============================================================================

  MYPROJECT: A software package for whatever.

  Copyright (c) University College London (UCL). All rights reserved.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

  See LICENSE.txt in the top level directory for details.

=============================================================================*/

#include "mpQQuickVTKView.h"
#include <vtkRendererCollection.h>
#include <vtkEventQtSlotConnect.h>
#include <QVTKInteractorAdapter.h>
#include <QMutexLocker>

namespace mp {

//-----------------------------------------------------------------------------
QQuickVTKView::~QQuickVTKView()
{
  if (m_VTKRenderWindow)
  {
    m_VTKRenderWindowInteractor->Disable();
    m_VTKRenderWindow->SetInteractor(nullptr);
#ifdef BUILD_VTK_OpenGL2
    m_VTKRenderWindow->SetReadyForRendering(false);
#endif
    m_VTKRenderWindow->RemoveAllObservers();
    vtkRendererCollection *c = m_VTKRenderWindow->GetRenderers();
    vtkRenderer *v = nullptr;
    while(v = c->GetNextItem(), v != nullptr)
    {
      m_VTKRenderWindow->RemoveRenderer(v);
    }
  }
}

//-----------------------------------------------------------------------------
QQuickVTKView::QQuickVTKView(QWindow * parent)
: QQuickView(parent)
, m_Mutex(QMutex::NonRecursive)
, m_VTKRenderWindow(nullptr)
, m_VTKRenderWindowInteractor(nullptr)
, m_VTKInteractorStyleMultiTouchCamera(nullptr)
, m_EraseBeforeVTKRendering(true)
{
  this->Init();
}

//-----------------------------------------------------------------------------
QQuickVTKView::QQuickVTKView(QQmlEngine * engine, QWindow * parent)
: QQuickView(engine, parent)
, m_Mutex(QMutex::NonRecursive)
, m_VTKRenderWindow(nullptr)
, m_VTKRenderWindowInteractor(nullptr)
, m_VTKInteractorStyleMultiTouchCamera(nullptr)
, m_EraseBeforeVTKRendering(true)
{
  this->Init();
}

//-----------------------------------------------------------------------------
QQuickVTKView::QQuickVTKView(const QUrl & source, QWindow * parent)
: QQuickView(source, parent)
, m_Mutex(QMutex::NonRecursive)
, m_VTKRenderWindow(nullptr)
, m_VTKRenderWindowInteractor(nullptr)
, m_VTKInteractorStyleMultiTouchCamera(nullptr)
, m_EraseBeforeVTKRendering(true)
{
  this->Init();
}

//-----------------------------------------------------------------------------
void QQuickVTKView::Init()
{
  m_VTKRenderWindow = vtkExternalOpenGLRenderWindow::New();

  m_VTKInteractorStyleMultiTouchCamera = vtkInteractorStyleMultiTouchCamera::New();

  m_VTKRenderWindowInteractor = vtkRenderWindowInteractor::New();
  m_VTKRenderWindowInteractor->SetRenderWindow(m_VTKRenderWindow);
  m_VTKRenderWindowInteractor->SetInteractorStyle(m_VTKInteractorStyleMultiTouchCamera);

  // This is to stop interactor triggering Render(),
  // as the rendering is done in the scene graph thread,
  // but the interaction is done in the gui thread.
  m_VTKRenderWindowInteractor->SetEnableRender(false);

  m_VTKInteractorAdapter = new QVTKInteractorAdapter(this);
  m_VTKInteractorAdapter->SetDevicePixelRatio(this->devicePixelRatio());

  m_EventSlotConnector = vtkSmartPointer<vtkEventQtSlotConnect>::New();

  connect(this, SIGNAL(beforeRendering()), this, SLOT(Render()), Qt::DirectConnection);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::AddRenderer(vtkRenderer* r)
{
  m_VTKRenderWindow->AddRenderer(r);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::RemoveRenderer(vtkRenderer *r)
{
  m_VTKRenderWindow->RemoveRenderer(r);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::SetEraseBeforeVTKRendering(bool b)
{
  m_EraseBeforeVTKRendering = b;
  m_VTKRenderWindow->SetErase(m_EraseBeforeVTKRendering);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::Render()
{
  emit beforeVTKRendering();

  QMutexLocker lock(&m_Mutex);

  m_VTKRenderWindow->Render();
  emit afterVTKRendering();
}

//-----------------------------------------------------------------------------
void QQuickVTKView::SetEnabled(bool isEnabled)
{
  if (isEnabled)
  {
    m_VTKRenderWindowInteractor->Enable();
  }
  else
  {
    m_VTKRenderWindowInteractor->Disable();
  }
}

//-----------------------------------------------------------------------------
bool QQuickVTKView::event(QEvent *e)
{
  if(e->type() == QEvent::TouchBegin ||
     e->type() == QEvent::TouchUpdate ||
     e->type() == QEvent::TouchEnd
    )
  {
    QMutexLocker lock(&m_Mutex);
    if(m_VTKRenderWindow
#ifdef BUILD_VTK_OpenGL2
      && m_VTKRenderWindow->GetReadyForRendering()
#endif
      )
    {
      m_VTKInteractorAdapter->ProcessEvent(e, m_VTKRenderWindow->GetInteractor());
      if (e->isAccepted())
      {
        return true;
      }
    }
  }
  return QQuickView::event(e);
}

//-----------------------------------------------------------------------------
bool QQuickVTKView::ProcessEvent(QEvent* e)
{
  QMutexLocker lock(&m_Mutex);
  if (m_VTKRenderWindow
#ifdef BUILD_VTK_OpenGL2
    && m_VTKRenderWindow->GetReadyForRendering()
#endif
    )
  {
    return m_VTKInteractorAdapter->ProcessEvent(e, m_VTKRenderWindowInteractor);
  }
  return false;
}

//-----------------------------------------------------------------------------
void QQuickVTKView::mousePressEvent(QMouseEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::mouseMoveEvent(QMouseEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::mouseReleaseEvent(QMouseEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::mouseDoubleClickEvent(QMouseEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::keyPressEvent(QKeyEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::keyReleaseEvent(QKeyEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::enterEvent(QEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::leaveEvent(QEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
void QQuickVTKView::wheelEvent(QWheelEvent* event)
{
  this->ProcessEvent(event);
}

//-----------------------------------------------------------------------------
} // end namespace
<|endoftext|>


<commit_before>#include <stdint.h>

#include <QtEndian>

#include "viewer.h"
#include "ui_viewer.h"

Viewer::Viewer(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Viewer)
{
    ui->setupUi(this);
}

Viewer::~Viewer()
{
    delete ui;
}

void Viewer::message(QString message)
{
    ui->statusLabel->setText(message);
    ui->statusLabel->setStyleSheet("color: black; font-weight: normal;");
}

void Viewer::error(const char *message, int error)
{
    ui->statusLabel->setText(QString("%1 (%2)").arg(message).arg(error));
    ui->statusLabel->setStyleSheet("color: red; font-weight: bold;");
}

void Viewer::on_scanButton_clicked()
{
    int timeout = ui->timeoutSlider->value();

    if (timeout == ui->timeoutSlider->maximum())
        timeout = -1;
    else
        timeout *= 1000;

    Fingerprint *fingerprint;
    try {
        fingerprint = scanner->getFingerprint(timeout);
    } catch (ScannerTimeout &e) {
        message("Timeout...");
        return;
    } catch (ScannerException &e) {
        error(e.what(), e.code());
        return;
    }

    QString status;
    scene.clear();
    ui->templateText->clear();

    if (fingerprint->image) {
        QImage *image = fingerprint->image->getImage();
        pixmap = QPixmap::fromImage(*image);
        scene.addPixmap(pixmap);
        scene.setSceneRect(pixmap.rect());
        scene.addRect(pixmap.rect(), QPen(Qt::blue), QBrush());
        message(QString("Obtained %1x%2 pixels large image").arg(image->width()).arg(image->height()));
        delete image;
    }

    if (fingerprint->minutiaeRecord) {
        ui->templateText->setPlainText(fingerprint->minutiaeRecord->getRecord());

        if (fingerprint->image) {
            for (std::list<FingerprintMinutia>::iterator m = fingerprint->minutiaeRecord->minutiae.begin(); m != fingerprint->minutiaeRecord->minutiae.end(); m++) {
                scene.addRect(m->x - 1, m->y - 1, 3, 3, QPen(Qt::red), QBrush());
                scene.addRect(m->x - 2, m->y - 2, 5, 5, QPen(Qt::red), QBrush());
            }
        }
    }

    ui->imageView->setScene(&scene);

    delete fingerprint;
}

void Viewer::on_onOffButton_clicked()
{
    if (!enabled) {
        try {
            scanner = new Scanner();
            message(QString("Turned on scanner '%1'").arg(scanner->getName()));
            enabled = true;
        } catch (ScannerException &e) {
            error(e.what(), e.code());
        }
    } else {
        delete scanner;
        ui->templateText->clear();
        scene.clear();
        message("Turned off scanner");
        enabled = false;
    }

    ui->scanButton->setEnabled(enabled);
    ui->timeoutSlider->setEnabled(enabled);
    ui->onOffButton->setText(enabled ? "Turn off" : "Turn on");
}

void Viewer::on_timeoutSlider_sliderMoved(int position)
{
    QString timeout;

    if (position == ui->timeoutSlider->maximum())
        timeout = QString("infinite");
    else if (position == 0)
        timeout = QString("none");
    else if (position == 1)
        timeout = QString("1 second");
    else
        timeout = QString("%1 seconds").arg(position);

    ui->timeoutLabel->setText(QString("Timeout: %1").arg(timeout));
}
<commit_msg>viewer: Initialise critical member<commit_after>#include <stdint.h>

#include <QtEndian>

#include "viewer.h"
#include "ui_viewer.h"

Viewer::Viewer(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Viewer),
    enabled(false)
{
    ui->setupUi(this);
}

Viewer::~Viewer()
{
    delete ui;
}

void Viewer::message(QString message)
{
    ui->statusLabel->setText(message);
    ui->statusLabel->setStyleSheet("color: black; font-weight: normal;");
}

void Viewer::error(const char *message, int error)
{
    ui->statusLabel->setText(QString("%1 (%2)").arg(message).arg(error));
    ui->statusLabel->setStyleSheet("color: red; font-weight: bold;");
}

void Viewer::on_scanButton_clicked()
{
    int timeout = ui->timeoutSlider->value();

    if (timeout == ui->timeoutSlider->maximum())
        timeout = -1;
    else
        timeout *= 1000;

    Fingerprint *fingerprint;
    try {
        fingerprint = scanner->getFingerprint(timeout);
    } catch (ScannerTimeout &e) {
        message("Timeout...");
        return;
    } catch (ScannerException &e) {
        error(e.what(), e.code());
        return;
    }

    QString status;
    scene.clear();
    ui->templateText->clear();

    if (fingerprint->image) {
        QImage *image = fingerprint->image->getImage();
        pixmap = QPixmap::fromImage(*image);
        scene.addPixmap(pixmap);
        scene.setSceneRect(pixmap.rect());
        scene.addRect(pixmap.rect(), QPen(Qt::blue), QBrush());
        message(QString("Obtained %1x%2 pixels large image").arg(image->width()).arg(image->height()));
        delete image;
    }

    if (fingerprint->minutiaeRecord) {
        ui->templateText->setPlainText(fingerprint->minutiaeRecord->getRecord());

        if (fingerprint->image) {
            for (std::list<FingerprintMinutia>::iterator m = fingerprint->minutiaeRecord->minutiae.begin(); m != fingerprint->minutiaeRecord->minutiae.end(); m++) {
                scene.addRect(m->x - 1, m->y - 1, 3, 3, QPen(Qt::red), QBrush());
                scene.addRect(m->x - 2, m->y - 2, 5, 5, QPen(Qt::red), QBrush());
            }
        }
    }

    ui->imageView->setScene(&scene);

    delete fingerprint;
}

void Viewer::on_onOffButton_clicked()
{
    if (!enabled) {
        try {
            scanner = new Scanner();
            message(QString("Turned on scanner '%1'").arg(scanner->getName()));
            enabled = true;
        } catch (ScannerException &e) {
            error(e.what(), e.code());
        }
    } else {
        delete scanner;
        ui->templateText->clear();
        scene.clear();
        message("Turned off scanner");
        enabled = false;
    }

    ui->scanButton->setEnabled(enabled);
    ui->timeoutSlider->setEnabled(enabled);
    ui->onOffButton->setText(enabled ? "Turn off" : "Turn on");
}

void Viewer::on_timeoutSlider_sliderMoved(int position)
{
    QString timeout;

    if (position == ui->timeoutSlider->maximum())
        timeout = QString("infinite");
    else if (position == 0)
        timeout = QString("none");
    else if (position == 1)
        timeout = QString("1 second");
    else
        timeout = QString("%1 seconds").arg(position);

    ui->timeoutLabel->setText(QString("Timeout: %1").arg(timeout));
}
<|endoftext|>


<commit_before>#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include "wowfoot.h"
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "win32.h"
#include "util/exception.h"

using namespace std;

class SourceHandler : public RequestHandler {
public:
	virtual ResponseData* handleRequest(const char* urlPart, MHD_Connection*);
	virtual void cleanup(ResponseData*) __attribute__((noreturn));
	virtual void unload(const char*, size_t) {}
	virtual void load() {}
};

static int sh(const char* cmd) {
	printf("%s\n", cmd);
	return system(cmd);
}

ResponseData* SourceHandler::handleRequest(const char* urlPart, MHD_Connection* conn) {
	assert(*urlPart == 0);
	int res;

	// call TAR
	char* cwd = getcwd(NULL, 0);
	ERRNO(chdir("../.."));
	ERRNO(sh("tar -czf t.tgz -X wowfoot/.gitignore --exclude=.git wowfoot"));
	ERRNO(chdir(cwd));
	free(cwd);

	// send file
	int code;
	uint64_t size;
	time_t fileDate;
	char* text = readFileForHTTP("../../t.tgz", size, 0, fileDate, code);
	EASSERT(text);
	MHD_Response* resp = MHD_create_response_from_data(size, text, 1, 0);
	assert(resp);
	{
		// todo: correct mime type?
		res = MHD_add_response_header(resp, MHD_HTTP_HEADER_CONTENT_TYPE, "archive/tgz");
		assert(res == MHD_YES);
		// todo: rename file; have browser treat it as an attachment, so it gets saved to disk.
		res = MHD_add_response_header(resp, "Content-Disposition", "attachment; filename=\"source.tgz\"");
		assert(res == MHD_YES);
	}
	res = MHD_queue_response(conn, code, resp);
	assert(res == MHD_YES);
	MHD_destroy_response(resp);
	return NULL;
}

void SourceHandler::cleanup(ResponseData*) {
	// this function should never be called.
	abort();
}

void mountSource() {
	insertExactPattern(PatternPair("/source", new SourceHandler()));
}
<commit_msg>sourceHandler: .git/info/exclude<commit_after>#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include "wowfoot.h"
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "win32.h"
#include "util/exception.h"

using namespace std;

class SourceHandler : public RequestHandler {
public:
	virtual ResponseData* handleRequest(const char* urlPart, MHD_Connection*);
	virtual void cleanup(ResponseData*) __attribute__((noreturn));
	virtual void unload(const char*, size_t) {}
	virtual void load() {}
};

static int sh(const char* cmd) {
	printf("%s\n", cmd);
	return system(cmd);
}

ResponseData* SourceHandler::handleRequest(const char* urlPart, MHD_Connection* conn) {
	assert(*urlPart == 0);
	int res;

	// call TAR
	char* cwd = getcwd(NULL, 0);
	ERRNO(chdir("../.."));
	ERRNO(sh("tar -czf t.tgz -X wowfoot/.gitignore -X wowfoot/.git/info/exclude --exclude=.git wowfoot"));
	ERRNO(chdir(cwd));
	free(cwd);

	// send file
	int code;
	uint64_t size;
	time_t fileDate;
	char* text = readFileForHTTP("../../t.tgz", size, 0, fileDate, code);
	EASSERT(text);
	MHD_Response* resp = MHD_create_response_from_data(size, text, 1, 0);
	assert(resp);
	{
		// todo: correct mime type?
		res = MHD_add_response_header(resp, MHD_HTTP_HEADER_CONTENT_TYPE, "archive/tgz");
		assert(res == MHD_YES);
		// todo: rename file; have browser treat it as an attachment, so it gets saved to disk.
		res = MHD_add_response_header(resp, "Content-Disposition", "attachment; filename=\"source.tgz\"");
		assert(res == MHD_YES);
	}
	res = MHD_queue_response(conn, code, resp);
	assert(res == MHD_YES);
	MHD_destroy_response(resp);
	return NULL;
}

void SourceHandler::cleanup(ResponseData*) {
	// this function should never be called.
	abort();
}

void mountSource() {
	insertExactPattern(PatternPair("/source", new SourceHandler()));
}
<|endoftext|>


<commit_before>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include <cstdio>
#include <sys/stat.h>
#include "core/clever.h"
#include "core/value.h"
#include "core/vm.h"
#include "modules/std/file/cfile.h"
#include "modules/std/file/file.h"
#include "modules/std/core/function.h"
#include "types/type.h"

namespace clever { namespace modules { namespace std {

namespace file {

static CLEVER_FUNCTION(rename)
{
	if (!clever_static_check_args("ss")) {
		return;
	}

	const char* from = args[0]->getStr()->c_str();
	const char* to = args[1]->getStr()->c_str();
	struct stat info;

	// Check if file from exists
	if (stat(from, &info) != 0) {
		clever_throw("File FROM does not exists.");
		return;
	}

	result->setBool(::std::rename(from, to) == 0);
}

static CLEVER_FUNCTION(remove)
{
	if (!clever_static_check_args("s")) {
		return;
	}

	const char* file = args[0]->getStr()->c_str();
	struct stat info;

	// Check if file from exists
	if (stat(file, &info) != 0) {
		clever_throw("File does not exists.");
		return;
	}

	result->setBool(::std::remove(file) == 0);
}

static CLEVER_FUNCTION(file_exists)
{
	if (!clever_static_check_args("s")) {
		return;
	}

	const char* file = args[0]->getStr()->c_str();
	struct stat info;

	result->setBool(stat(file, &info) == 0);
}

static CLEVER_FUNCTION(is_dir)
{
	if (!clever_static_check_args("s")) {
		return;
	}

	const char* dir = args[0]->getStr()->c_str();
	struct stat info;

	if (stat(dir, &info) != 0) {
		result->setBool(false);
        return;
	}

	result->setBool((info.st_mode & S_IFMT) == S_IFDIR);
}

} // clever::modules::std::file

/// Initializes Standard File module
CLEVER_MODULE_INIT(FileModule)
{
	addFunction(new Function("rename",      &CLEVER_NS_FNAME(file, rename)));
	addFunction(new Function("remove",      &CLEVER_NS_FNAME(file, remove)));
	addFunction(new Function("file_exists", &CLEVER_NS_FNAME(file, file_exists)));
	addFunction(new Function("is_dir",      &CLEVER_NS_FNAME(file, is_dir)));

	addType(new CFile);
}

}}} // clever::modules::std
<commit_msg>- Added glob() function to std.file module<commit_after>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include <cstdio>
#include <sys/stat.h>
#ifndef _WIN32
#include <glob.h>
#else
#include <windows.h>
#endif
#include "core/clever.h"
#include "core/value.h"
#include "core/vm.h"
#include "modules/std/file/cfile.h"
#include "modules/std/file/file.h"
#include "modules/std/core/function.h"
#include "modules/std/core/array.h"
#include "types/type.h"

namespace clever { namespace modules { namespace std {

namespace file {

// rename(String current_path, String new_path)
static CLEVER_FUNCTION(rename)
{
	if (!clever_static_check_args("ss")) {
		return;
	}

	const char* from = args[0]->getStr()->c_str();
	const char* to = args[1]->getStr()->c_str();
	struct stat info;

	// Check if file from exists
	if (stat(from, &info) != 0) {
		clever_throw("File FROM does not exists.");
		return;
	}

	result->setBool(::std::rename(from, to) == 0);
}

// remove(String path)
static CLEVER_FUNCTION(remove)
{
	if (!clever_static_check_args("s")) {
		return;
	}

	const char* file = args[0]->getStr()->c_str();
	struct stat info;

	// Check if file from exists
	if (stat(file, &info) != 0) {
		clever_throw("File does not exists.");
		return;
	}

	result->setBool(::std::remove(file) == 0);
}

// file_exists(String path)
static CLEVER_FUNCTION(file_exists)
{
	if (!clever_static_check_args("s")) {
		return;
	}

	const char* file = args[0]->getStr()->c_str();
	struct stat info;

	result->setBool(stat(file, &info) == 0);
}

// is_dir(String path)
static CLEVER_FUNCTION(is_dir)
{
	if (!clever_static_check_args("s")) {
		return;
	}

	const char* dir = args[0]->getStr()->c_str();
	struct stat info;

	if (stat(dir, &info) != 0) {
		result->setBool(false);
        return;
	}

	result->setBool((info.st_mode & S_IFMT) == S_IFDIR);
}

// glob(String pattern)
static CLEVER_FUNCTION(glob)
{
	if (!clever_static_check_args("s")) {
		return;
	}
	::std::vector< ::std::string> paths;

#ifndef _WIN32
	glob_t globbuf;

	globbuf.gl_offs = 0;

	glob(args[0]->getStr()->c_str(), GLOB_DOOFFS, NULL, &globbuf);

	for (size_t i = 0; i < globbuf.gl_pathc; ++i) {
		paths.push_back(globbuf.gl_pathv[i]);
	}

	if (globbuf.gl_pathc) {
		globfree(&globbuf);
	}
#else
	WIN32_FIND_DATA ffd;
	HANDLE hf = FindFirstFile(args[0]->getStr()->c_str(), &ffd);

	if (hf) {
		do {
			paths.push_back(ffd.cFileName);
		} while (FindNextFile(hf, &ffd) != 0);

		FindClose(hf);
	}
#endif

	if (paths.empty()) {
		result->setBool(false);
	} else {
		::std::vector< ::std::string>::const_iterator it(paths.begin()),
			end(paths.end());
		ArrayObject* array = new ArrayObject;

		for (; it != end; ++it) {
			Value* value = new Value;
			value->setStr(new StrObject(*it));

			array->getData().push_back(value);
		}
		result->setObj(CLEVER_ARRAY_TYPE, array);
	}
}

} // clever::modules::std::file

/// Initializes Standard File module
CLEVER_MODULE_INIT(FileModule)
{
	addFunction(new Function("rename",      &CLEVER_NS_FNAME(file, rename)));
	addFunction(new Function("remove",      &CLEVER_NS_FNAME(file, remove)));
	addFunction(new Function("file_exists", &CLEVER_NS_FNAME(file, file_exists)));
	addFunction(new Function("is_dir",      &CLEVER_NS_FNAME(file, is_dir)));
	addFunction(new Function("glob",        &CLEVER_NS_FNAME(file, glob)));

	addType(new CFile);
}

}}} // clever::modules::std
<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include "future.hh"
#include "queue.hh"

#include <experimental/optional>

/// \defgroup fiber-module Fibers
///
/// \brief Fibers of execution
///
/// Seastar continuations are normally short, but often chained to one
/// another, so that one continuation does a bit of work and then schedules
/// another continuation for later. Such chains can be long, and often even
/// involve loopings - see for example \ref repeat. We call such chains
/// "fibers" of execution.
///
/// These fibers are not threads - each is just a string of continuations -
/// but they share some common requirements with traditional threads.
/// For example, we want to avoid one fiber getting starved while a second
/// fiber continuously runs its continuations one after another.
/// As another example, fibers may want to communicate - e.g., one fiber
/// produces data that a second fiber consumes, and we wish to ensure that
/// both fibers get a chance to run, and that if one stops prematurely,
/// the other doesn't hang forever.
///
/// Consult the following table to see which APIs are useful for fiber tasks:
///
/// Task                                           | APIs
/// -----------------------------------------------|-------------------
/// Repeat a blocking task indefinitely            | \ref keep_doing()
/// Repeat a blocking task, then exit              | \ref repeat(), \ref do_until()
/// Provide mutual exclusion between two tasks     | \ref semaphore, \ref shared_mutex
/// Pass a stream of data between two fibers       | \ref seastar::pipe
/// Safely shut down a resource                    | \ref seastar::gate, \ref seastar::with_gate()
/// Hold on to an object while a fiber is running  | \ref do_with()
///

/// Seastar API namespace
namespace seastar {

/// \addtogroup fiber-module
/// @{

class broken_pipe_exception : public std::exception {
public:
    virtual const char* what() const noexcept {
        return "Broken pipe";
    }
};

class unread_overflow_exception : public std::exception {
public:
    virtual const char* what() const noexcept {
        return "pipe_reader::unread() overflow";
    }
};

/// \cond internal
namespace internal {
template <typename T>
class pipe_buffer {
private:
    queue<std::experimental::optional<T>> _buf;
    bool _read_open = true;
    bool _write_open = true;
public:
    pipe_buffer(size_t size) : _buf(size) {}
    future<std::experimental::optional<T>> read() {
        return _buf.pop_eventually();
    }
    future<> write(T&& data) {
        return _buf.push_eventually(std::move(data));
    }
    bool readable() const {
        return _write_open || !_buf.empty();
    }
    bool writeable() const {
        return _read_open;
    }
    bool close_read() {
        // If a writer blocking (on a full queue), need to stop it.
        if (_buf.full()) {
            _buf.abort(std::make_exception_ptr(broken_pipe_exception()));
        }
        _read_open = false;
        return !_write_open;
    }
    bool close_write() {
        // If the queue is empty, write the EOF (disengaged optional) to the
        // queue to wake a blocked reader. If the queue is not empty, there is
        // no need to write the EOF to the queue - the reader will return an
        // EOF when it sees that _write_open == false.
        if (_buf.empty()) {
            _buf.push({});
        }
        _write_open = false;
        return !_read_open;
    }
};
} // namespace internal
/// \endcond

template <typename T>
class pipe;

/// \brief Read side of a \ref seastar::pipe
///
/// The read side of a pipe, which allows only reading from the pipe.
/// A pipe_reader object cannot be created separately, but only as part of a
/// reader/writer pair through \ref seastar::pipe.
template <typename T>
class pipe_reader {
private:
    internal::pipe_buffer<T> *_bufp;
    std::experimental::optional<T> _unread;
    pipe_reader(internal::pipe_buffer<T> *bufp) : _bufp(bufp) { }
    friend class pipe<T>;
public:
    /// \brief Read next item from the pipe
    ///
    /// Returns a future value, which is fulfilled when the pipe's buffer
    /// becomes non-empty, or the write side is closed. The value returned
    /// is an optional<T>, which is disengaged to mark and end of file
    /// (i.e., the write side was closed, and we've read everything it sent).
    future<std::experimental::optional<T>> read() {
        if (_unread) {
            auto&& ret = std::move(*_unread);
            _unread = {};
            return make_ready_future<std::experimental::optional<T>>(ret);
        }
        if (_bufp->readable()) {
            return _bufp->read();
        } else {
            return make_ready_future<std::experimental::optional<T>>();
        }
    }
    /// \brief Return an item to the front of the pipe
    ///
    /// Pushes the given item to the front of the pipe, so it will be
    /// returned by the next read() call. The typical use case is to
    /// unread() the last item returned by read().
    /// More generally, it is legal to unread() any item, not just one
    /// previously returned by read(), but note that the unread() is limited
    /// to just one item - two calls to unread() without an intervening call
    /// to read() will cause an exception.
    void unread(T&& item) {
        if (_unread) {
            throw unread_overflow_exception();
        }
        _unread = std::move(item);
    }
    ~pipe_reader() {
        if (_bufp && _bufp->close_read()) {
            delete _bufp;
        }
    }
    // Allow move, but not copy, of pipe_reader
    pipe_reader(pipe_reader&& other) : _bufp(other._bufp) {
        other._bufp = nullptr;
    }
    pipe_reader& operator=(pipe_reader&& other) {
        std::swap(_bufp, other._bufp);
    }
};

/// \brief Write side of a \ref seastar::pipe
///
/// The write side of a pipe, which allows only writing to the pipe.
/// A pipe_writer object cannot be created separately, but only as part of a
/// reader/writer pair through \ref seastar::pipe.
template <typename T>
class pipe_writer {
private:
    internal::pipe_buffer<T> *_bufp;
    pipe_writer(internal::pipe_buffer<T> *bufp) : _bufp(bufp) { }
    friend class pipe<T>;
public:
    /// \brief Write an item to the pipe
    ///
    /// Returns a future value, which is fulfilled when the data was written
    /// to the buffer (when it become non-full). If the data could not be
    /// written because the read side was closed, an exception
    /// \ref broken_pipe_exception is returned in the future.
    future<> write(T&& data) {
        if (_bufp->writeable()) {
            return _bufp->write(std::move(data));
        } else {
            return make_exception_future<>(broken_pipe_exception());
        }
    }
    ~pipe_writer() {
        if (_bufp && _bufp->close_write()) {
            delete _bufp;
        }
    }
    // Allow move, but not copy, of pipe_writer
    pipe_writer(pipe_writer&& other) : _bufp(other._bufp) {
        other._bufp = nullptr;
    }
    pipe_writer& operator=(pipe_writer&& other) {
        std::swap(_bufp, other._bufp);
    }
};

/// \brief A fixed-size pipe for communicating between two fibers.
///
/// A pipe<T> is a mechanism to transfer data between two fibers, one
/// producing data, and the other consuming it. The fixed-size buffer also
/// ensures a balanced execution of the two fibers, because the producer
/// fiber blocks when it writes to a full pipe, until the consumer fiber gets
/// to run and read from the pipe.
///
/// A pipe<T> resembles a Unix pipe, in that it has a read side, a write side,
/// and a fixed-sized buffer between them, and supports either end to be closed
/// independently (and EOF or broken pipe when using the other side).
/// A pipe<T> object holds the reader and write sides of the pipe as two
/// separate objects. These objects can be moved into two different fibers.
/// Importantly, if one of the pipe ends is destroyed (i.e., the continuations
/// capturing it end), the other end of the pipe will stop blocking, so the
/// other fiber will not hang.
///
/// The pipe's read and write interfaces are future-based blocking. I.e., the
/// write() and read() methods return a future which is fulfilled when the
/// operation is complete. The pipe is single-reader single-writer, meaning
/// that until the future returned by read() is fulfilled, read() must not be
/// called again (and same for write).
///
/// Note: The pipe reader and writer are movable, but *not* copyable. It is
/// often convenient to wrap each end in a shared pointer, so it can be
/// copied (e.g., used in an std::function which needs to be copyable) or
/// easily captured into multiple continuations.
template <typename T>
class pipe {
public:
    pipe_reader<T> reader;
    pipe_writer<T> writer;
    explicit pipe(size_t size) : pipe(new internal::pipe_buffer<T>(size)) { }
private:
    pipe(internal::pipe_buffer<T> *bufp) : reader(bufp), writer(bufp) { }
};

/// @}

} // namespace seastar
<commit_msg>core: fix pipe unread<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include "future.hh"
#include "queue.hh"

#include <experimental/optional>

/// \defgroup fiber-module Fibers
///
/// \brief Fibers of execution
///
/// Seastar continuations are normally short, but often chained to one
/// another, so that one continuation does a bit of work and then schedules
/// another continuation for later. Such chains can be long, and often even
/// involve loopings - see for example \ref repeat. We call such chains
/// "fibers" of execution.
///
/// These fibers are not threads - each is just a string of continuations -
/// but they share some common requirements with traditional threads.
/// For example, we want to avoid one fiber getting starved while a second
/// fiber continuously runs its continuations one after another.
/// As another example, fibers may want to communicate - e.g., one fiber
/// produces data that a second fiber consumes, and we wish to ensure that
/// both fibers get a chance to run, and that if one stops prematurely,
/// the other doesn't hang forever.
///
/// Consult the following table to see which APIs are useful for fiber tasks:
///
/// Task                                           | APIs
/// -----------------------------------------------|-------------------
/// Repeat a blocking task indefinitely            | \ref keep_doing()
/// Repeat a blocking task, then exit              | \ref repeat(), \ref do_until()
/// Provide mutual exclusion between two tasks     | \ref semaphore, \ref shared_mutex
/// Pass a stream of data between two fibers       | \ref seastar::pipe
/// Safely shut down a resource                    | \ref seastar::gate, \ref seastar::with_gate()
/// Hold on to an object while a fiber is running  | \ref do_with()
///

/// Seastar API namespace
namespace seastar {

/// \addtogroup fiber-module
/// @{

class broken_pipe_exception : public std::exception {
public:
    virtual const char* what() const noexcept {
        return "Broken pipe";
    }
};

class unread_overflow_exception : public std::exception {
public:
    virtual const char* what() const noexcept {
        return "pipe_reader::unread() overflow";
    }
};

/// \cond internal
namespace internal {
template <typename T>
class pipe_buffer {
private:
    queue<std::experimental::optional<T>> _buf;
    bool _read_open = true;
    bool _write_open = true;
public:
    pipe_buffer(size_t size) : _buf(size) {}
    future<std::experimental::optional<T>> read() {
        return _buf.pop_eventually();
    }
    future<> write(T&& data) {
        return _buf.push_eventually(std::move(data));
    }
    bool readable() const {
        return _write_open || !_buf.empty();
    }
    bool writeable() const {
        return _read_open;
    }
    bool close_read() {
        // If a writer blocking (on a full queue), need to stop it.
        if (_buf.full()) {
            _buf.abort(std::make_exception_ptr(broken_pipe_exception()));
        }
        _read_open = false;
        return !_write_open;
    }
    bool close_write() {
        // If the queue is empty, write the EOF (disengaged optional) to the
        // queue to wake a blocked reader. If the queue is not empty, there is
        // no need to write the EOF to the queue - the reader will return an
        // EOF when it sees that _write_open == false.
        if (_buf.empty()) {
            _buf.push({});
        }
        _write_open = false;
        return !_read_open;
    }
};
} // namespace internal
/// \endcond

template <typename T>
class pipe;

/// \brief Read side of a \ref seastar::pipe
///
/// The read side of a pipe, which allows only reading from the pipe.
/// A pipe_reader object cannot be created separately, but only as part of a
/// reader/writer pair through \ref seastar::pipe.
template <typename T>
class pipe_reader {
private:
    internal::pipe_buffer<T> *_bufp;
    std::experimental::optional<T> _unread;
    pipe_reader(internal::pipe_buffer<T> *bufp) : _bufp(bufp) { }
    friend class pipe<T>;
public:
    /// \brief Read next item from the pipe
    ///
    /// Returns a future value, which is fulfilled when the pipe's buffer
    /// becomes non-empty, or the write side is closed. The value returned
    /// is an optional<T>, which is disengaged to mark and end of file
    /// (i.e., the write side was closed, and we've read everything it sent).
    future<std::experimental::optional<T>> read() {
        if (_unread) {
            auto ret = std::move(*_unread);
            _unread = {};
            return make_ready_future<std::experimental::optional<T>>(std::move(ret));
        }
        if (_bufp->readable()) {
            return _bufp->read();
        } else {
            return make_ready_future<std::experimental::optional<T>>();
        }
    }
    /// \brief Return an item to the front of the pipe
    ///
    /// Pushes the given item to the front of the pipe, so it will be
    /// returned by the next read() call. The typical use case is to
    /// unread() the last item returned by read().
    /// More generally, it is legal to unread() any item, not just one
    /// previously returned by read(), but note that the unread() is limited
    /// to just one item - two calls to unread() without an intervening call
    /// to read() will cause an exception.
    void unread(T&& item) {
        if (_unread) {
            throw unread_overflow_exception();
        }
        _unread = std::move(item);
    }
    ~pipe_reader() {
        if (_bufp && _bufp->close_read()) {
            delete _bufp;
        }
    }
    // Allow move, but not copy, of pipe_reader
    pipe_reader(pipe_reader&& other) : _bufp(other._bufp) {
        other._bufp = nullptr;
    }
    pipe_reader& operator=(pipe_reader&& other) {
        std::swap(_bufp, other._bufp);
    }
};

/// \brief Write side of a \ref seastar::pipe
///
/// The write side of a pipe, which allows only writing to the pipe.
/// A pipe_writer object cannot be created separately, but only as part of a
/// reader/writer pair through \ref seastar::pipe.
template <typename T>
class pipe_writer {
private:
    internal::pipe_buffer<T> *_bufp;
    pipe_writer(internal::pipe_buffer<T> *bufp) : _bufp(bufp) { }
    friend class pipe<T>;
public:
    /// \brief Write an item to the pipe
    ///
    /// Returns a future value, which is fulfilled when the data was written
    /// to the buffer (when it become non-full). If the data could not be
    /// written because the read side was closed, an exception
    /// \ref broken_pipe_exception is returned in the future.
    future<> write(T&& data) {
        if (_bufp->writeable()) {
            return _bufp->write(std::move(data));
        } else {
            return make_exception_future<>(broken_pipe_exception());
        }
    }
    ~pipe_writer() {
        if (_bufp && _bufp->close_write()) {
            delete _bufp;
        }
    }
    // Allow move, but not copy, of pipe_writer
    pipe_writer(pipe_writer&& other) : _bufp(other._bufp) {
        other._bufp = nullptr;
    }
    pipe_writer& operator=(pipe_writer&& other) {
        std::swap(_bufp, other._bufp);
    }
};

/// \brief A fixed-size pipe for communicating between two fibers.
///
/// A pipe<T> is a mechanism to transfer data between two fibers, one
/// producing data, and the other consuming it. The fixed-size buffer also
/// ensures a balanced execution of the two fibers, because the producer
/// fiber blocks when it writes to a full pipe, until the consumer fiber gets
/// to run and read from the pipe.
///
/// A pipe<T> resembles a Unix pipe, in that it has a read side, a write side,
/// and a fixed-sized buffer between them, and supports either end to be closed
/// independently (and EOF or broken pipe when using the other side).
/// A pipe<T> object holds the reader and write sides of the pipe as two
/// separate objects. These objects can be moved into two different fibers.
/// Importantly, if one of the pipe ends is destroyed (i.e., the continuations
/// capturing it end), the other end of the pipe will stop blocking, so the
/// other fiber will not hang.
///
/// The pipe's read and write interfaces are future-based blocking. I.e., the
/// write() and read() methods return a future which is fulfilled when the
/// operation is complete. The pipe is single-reader single-writer, meaning
/// that until the future returned by read() is fulfilled, read() must not be
/// called again (and same for write).
///
/// Note: The pipe reader and writer are movable, but *not* copyable. It is
/// often convenient to wrap each end in a shared pointer, so it can be
/// copied (e.g., used in an std::function which needs to be copyable) or
/// easily captured into multiple continuations.
template <typename T>
class pipe {
public:
    pipe_reader<T> reader;
    pipe_writer<T> writer;
    explicit pipe(size_t size) : pipe(new internal::pipe_buffer<T>(size)) { }
private:
    pipe(internal::pipe_buffer<T> *bufp) : reader(bufp), writer(bufp) { }
};

/// @}

} // namespace seastar
<|endoftext|>


<commit_before>// Copyright 2014 BVLC and contributors.

#include <vector>

#include "cuda_runtime.h"
#include "gtest/gtest.h"
#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/filler.hpp"
#include "caffe/vision_layers.hpp"
#include "caffe/test/test_gradient_check_util.hpp"

#include "caffe/test/test_caffe_main.hpp"

namespace caffe {

extern cudaDeviceProp CAFFE_TEST_CUDA_PROP;

template <typename Dtype>
class ArgMaxLayerTest : public ::testing::Test {
 protected:
  ArgMaxLayerTest()
      : blob_bottom_(new Blob<Dtype>(20, 10, 1, 1)),
        blob_top_(new Blob<Dtype>()) {
    Caffe::set_random_seed(1701);
    // fill the values
    FillerParameter filler_param;
    GaussianFiller<Dtype> filler(filler_param);
    filler.Fill(this->blob_bottom_);
    blob_bottom_vec_.push_back(blob_bottom_);
    blob_top_vec_.push_back(blob_top_);
  }
  virtual ~ArgMaxLayerTest() { delete blob_bottom_; delete blob_top_; }
  Blob<Dtype>* const blob_bottom_;
  Blob<Dtype>* const blob_top_;
  vector<Blob<Dtype>*> blob_bottom_vec_;
  vector<Blob<Dtype>*> blob_top_vec_;
};

typedef ::testing::Types<float, double> Dtypes;
TYPED_TEST_CASE(ArgMaxLayerTest, Dtypes);

TYPED_TEST(ArgMaxLayerTest, TestSetup) {
  LayerParameter layer_param;
  ThresholdLayer<TypeParam> layer(layer_param);
  layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  EXPECT_EQ(this->blob_top_->num(), this->bottom_top_->num());
  EXPECT_EQ(this->blob_top_->channels(), 1);
}

TYPED_TEST(ArgMaxLayerTest, TestSetupMaxVal) {
  LayerParameter layer_param;
  ArgMaxParameter* argmax_param = layer_param.mutable_argmax_param();
  argmax_param->set_out_max_val(true);
  ThresholdLayer<TypeParam> layer(layer_param);
  layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  EXPECT_EQ(this->blob_top_->num(), this->bottom_top_->num());
  EXPECT_EQ(this->blob_top_->channels(), 2);
}

TYPED_TEST(ArgMaxLayerTest, TestCPU) {
  LayerParameter layer_param;
  Caffe::set_mode(Caffe::CPU);
  ArgMaxLayer<TypeParam> layer(layer_param);
  layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  layer.Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
  // Now, check values
  const TypeParam* bottom_data = this->blob_bottom_->cpu_data();
  const TypeParam* top_data = this->blob_top_->cpu_data();
  int max_ind;
  TypeParam max_val;
  int num = this->blob_bottom_->num();
  int dim = this->blob_bottom_->count() / num;
  for (int i = 0; i < num; ++i) {
    EXPECT_GE(top_data[i], 0);
    EXPECT_LE(top_data[i], dim);
    max_ind = top_data[i];
    max_val = bottom_data[i * dim + max_ind];
    for (int j = 0; j < dim; ++j) {
      EXPECT_LE(bottom_data[i * dim + j], max_val);
    }
  }
}

TYPED_TEST(ArgMaxLayerTest, TestCPUMaxVal) {
  LayerParameter layer_param;
  Caffe::set_mode(Caffe::CPU);
  ArgMaxParameter* argmax_param = layer_param.mutable_argmax_param();
  argmax_param->set_out_max_val(true);
  ArgMaxLayer<TypeParam> layer(layer_param);
  layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  layer.Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
  // Now, check values
  const TypeParam* bottom_data = this->blob_bottom_->cpu_data();
  const TypeParam* top_data = this->blob_top_->cpu_data();
  int max_ind;
  TypeParam max_val;
  int num = this->blob_bottom_->num();
  int dim = this->blob_bottom_->count() / num;
  for (int i = 0; i < num; ++i) {
    EXPECT_GE(top_data[i], 0);
    EXPECT_LE(top_data[i], dim);
    max_ind = top_data[i * 2];
    max_val = top_data[i * 2 + 1];
    EXPECT_EQ(bottom_data[i * dim + max_ind],max_val);
    for (int j = 0; j < dim; ++j) {
      EXPECT_LE(bottom_data[i * dim + j], max_val);
    }
  }
}

}  // namespace caffe
<commit_msg>Fixed name of ArgMaxLayerParameter<commit_after>// Copyright 2014 BVLC and contributors.

#include <vector>

#include "cuda_runtime.h"
#include "gtest/gtest.h"
#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/filler.hpp"
#include "caffe/vision_layers.hpp"
#include "caffe/test/test_gradient_check_util.hpp"

#include "caffe/test/test_caffe_main.hpp"

namespace caffe {

extern cudaDeviceProp CAFFE_TEST_CUDA_PROP;

template <typename Dtype>
class ArgMaxLayerTest : public ::testing::Test {
 protected:
  ArgMaxLayerTest()
      : blob_bottom_(new Blob<Dtype>(20, 10, 1, 1)),
        blob_top_(new Blob<Dtype>()) {
    Caffe::set_random_seed(1701);
    // fill the values
    FillerParameter filler_param;
    GaussianFiller<Dtype> filler(filler_param);
    filler.Fill(this->blob_bottom_);
    blob_bottom_vec_.push_back(blob_bottom_);
    blob_top_vec_.push_back(blob_top_);
  }
  virtual ~ArgMaxLayerTest() { delete blob_bottom_; delete blob_top_; }
  Blob<Dtype>* const blob_bottom_;
  Blob<Dtype>* const blob_top_;
  vector<Blob<Dtype>*> blob_bottom_vec_;
  vector<Blob<Dtype>*> blob_top_vec_;
};

typedef ::testing::Types<float, double> Dtypes;
TYPED_TEST_CASE(ArgMaxLayerTest, Dtypes);

TYPED_TEST(ArgMaxLayerTest, TestSetup) {
  LayerParameter layer_param;
  ThresholdLayer<TypeParam> layer(layer_param);
  layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  EXPECT_EQ(this->blob_top_->num(), this->bottom_top_->num());
  EXPECT_EQ(this->blob_top_->channels(), 1);
}

TYPED_TEST(ArgMaxLayerTest, TestSetupMaxVal) {
  LayerParameter layer_param;
  ArgMaxLayerParameter* argmax_param = layer_param.mutable_argmax_param();
  argmax_param->set_out_max_val(true);
  ThresholdLayer<TypeParam> layer(layer_param);
  layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  EXPECT_EQ(this->blob_top_->num(), this->bottom_top_->num());
  EXPECT_EQ(this->blob_top_->channels(), 2);
}

TYPED_TEST(ArgMaxLayerTest, TestCPU) {
  LayerParameter layer_param;
  Caffe::set_mode(Caffe::CPU);
  ArgMaxLayer<TypeParam> layer(layer_param);
  layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  layer.Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
  // Now, check values
  const TypeParam* bottom_data = this->blob_bottom_->cpu_data();
  const TypeParam* top_data = this->blob_top_->cpu_data();
  int max_ind;
  TypeParam max_val;
  int num = this->blob_bottom_->num();
  int dim = this->blob_bottom_->count() / num;
  for (int i = 0; i < num; ++i) {
    EXPECT_GE(top_data[i], 0);
    EXPECT_LE(top_data[i], dim);
    max_ind = top_data[i];
    max_val = bottom_data[i * dim + max_ind];
    for (int j = 0; j < dim; ++j) {
      EXPECT_LE(bottom_data[i * dim + j], max_val);
    }
  }
}

TYPED_TEST(ArgMaxLayerTest, TestCPUMaxVal) {
  LayerParameter layer_param;
  Caffe::set_mode(Caffe::CPU);
  ArgMaxLayerParameter* argmax_param = layer_param.mutable_argmax_param();
  argmax_param->set_out_max_val(true);
  ArgMaxLayer<TypeParam> layer(layer_param);
  layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  layer.Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
  // Now, check values
  const TypeParam* bottom_data = this->blob_bottom_->cpu_data();
  const TypeParam* top_data = this->blob_top_->cpu_data();
  int max_ind;
  TypeParam max_val;
  int num = this->blob_bottom_->num();
  int dim = this->blob_bottom_->count() / num;
  for (int i = 0; i < num; ++i) {
    EXPECT_GE(top_data[i], 0);
    EXPECT_LE(top_data[i], dim);
    max_ind = top_data[i * 2];
    max_val = top_data[i * 2 + 1];
    EXPECT_EQ(bottom_data[i * dim + max_ind],max_val);
    for (int j = 0; j < dim; ++j) {
      EXPECT_LE(bottom_data[i * dim + j], max_val);
    }
  }
}

}  // namespace caffe
<|endoftext|>


<commit_before>// cvt.c - IEEE floating point formatting routines for FreeBSD
// from GNU libc-4.6.27
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. 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.
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.

#include <cassert>
#include <cstdlib>
#include <cmath>

namespace fixfmt {

constexpr size_t CVTBUFSIZE = 512;

char* cvt(double arg, int ndigits, int* decpt, int* sign, char* buf, int eflag)
{
  assert(ndigits >= 0);
  assert(ndigits < CVTBUFSIZE - 1);

  int r2;
  double fi;
  double fj;
  char* p;
  char* p1;

  r2 = 0;
  *sign = 0;
  p = &buf[0];
  if (arg < 0) {
    *sign = 1;
    arg = -arg;
  }

  // Split into integral and fractional parts.
  arg = modf(arg, &fi);
  p1 = &buf[CVTBUFSIZE];
  if (fi != 0) {
    // Have an integral part.  Render it right-to-left at the end of the buffer.
    p1 = &buf[CVTBUFSIZE];
    while (fi != 0) {
      fj = modf(fi / 10, &fi);
      *--p1 = (int)((fj + .03) * 10) + '0';
      r2++;
    }
    // Copy it to the beginning of the buffer.
    while (p1 < &buf[CVTBUFSIZE])
      *p++ = *p1++;
  }
  else if (arg > 0)
    // Fractional part only.  Scale it up until the first fractional digit
    // is nonzero.
    while ((fj = arg * 10) < 1) {
      arg = fj;
      r2--;
    }

  p1 = &buf[ndigits];
  if (eflag == 0)
    p1 += r2;
  *decpt = r2;
  if (p1 < &buf[0]) {
    buf[0] = '\0';
    return buf;
  }
  while (p <= p1 && p < &buf[CVTBUFSIZE]) {
    arg *= 10;
    arg = modf(arg, &fj);
    *p++ = (int) fj + '0';
  }
  if (p1 >= &buf[CVTBUFSIZE]) {
    buf[CVTBUFSIZE - 1] = '\0';
    return buf;
  }
  p = p1;
  *p1 += 5;
  while (*p1 > '9') {
    *p1 = '0';
    if (p1 > buf)
      ++*--p1;
    else {
      *p1 = '1';
      (*decpt)++;
      if (eflag == 0) {
        if (p > buf)
          *p = '0';
        p++;
      }
    }
  }
  *p = '\0';
  return buf;
}

char* ecvtbuf(double arg, int ndigits, int* decpt, int* sign, char* buf) {
  return cvt(arg, ndigits, decpt, sign, buf, 1);
}

char* fcvtbuf(double arg, int ndigits, int* decpt, int* sign, char* buf) {
  return cvt(arg, ndigits, decpt, sign, buf, 0);
}

}  // namespace fixfmt
<commit_msg>Remove cvt.cc.<commit_after><|endoftext|>