<commit_before>/*******************************************************************************
 * c7a/api/sort.hpp
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Alexander Noe <aleexnoe@gmail.com>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_API_SORT_HEADER
#define C7A_API_SORT_HEADER

#include <c7a/api/context.hpp>
#include <c7a/api/dia.hpp>
#include <c7a/api/function_stack.hpp>
#include <c7a/common/logger.hpp>
#include <c7a/net/collective_communication.hpp>
#include <c7a/net/flow_control_channel.hpp>
#include <c7a/net/flow_control_manager.hpp>
#include <c7a/net/group.hpp>

#include <cmath>

namespace c7a {
namespace api {

namespace {

template <typename ValueType>
struct TreeBuilder
{

    ValueType * tree_;
    ValueType * samples_;
    size_t    index_;
    size_t    ssplitter;

    TreeBuilder(ValueType* splitter_tree, // Target: tree. Size of 'number of splitter'
                ValueType* samples,       // Source: sorted splitters. Size of 'number of splitter'
                size_t ssplitter)         // Number of splitter
        : tree_(splitter_tree),
          samples_(samples),
          index_(0),
          ssplitter(ssplitter) {
        recurse(samples, samples + ssplitter, 1);
    }

    ssize_t   snum(ValueType* s) const {
        return (ssize_t)(s - samples_);
    }

    ValueType recurse(ValueType* lo, ValueType* hi, unsigned int treeidx) {

        // pick middle element as splitter
        ValueType* mid = lo + (ssize_t)(hi - lo) / 2;

        ValueType mykey = tree_[treeidx] = *mid;

        ValueType* midlo = mid, * midhi = mid + 1;

        if (2 * treeidx < ssplitter)
        {
            recurse(lo, midlo, 2 * treeidx + 0);

            return recurse(midhi, hi, 2 * treeidx + 1);
        }
        else
        {
            return mykey;
        }
    }
};

template <class T1, typename CompareFunction>
struct BucketEmitter
{
    static bool Equal(CompareFunction compare_function, const T1& ele1, const T1& ele2) {
        return !(compare_function(ele1, ele2) || compare_function(ele2, ele1));
    }

	static size_t RoundDown(size_t ele, size_t by) {
		return ((ele) & ~((by) - 1));
	}

    static void emitToBuckets(
        const T1* const a,
        const size_t n,
        const T1* const treearr, // Tree. sizeof |splitter|
        size_t k,                // Number of buckets
        size_t logK,
        std::vector<data::BlockWriter>& emitters,
        size_t actual_k,
        CompareFunction compare_function,
        const T1* const sorted_splitters,
        size_t prefix_elem,
        size_t total_elem) {

        const size_t stepsize = 2;

        size_t i = 0;
        for ( ; i < RoundDown(n, stepsize); i += stepsize)
        {

            size_t j0 = 1;
            const T1& el0 = a[i];
            size_t j1 = 1;
            const T1& el1 = a[i + 1];

            for (size_t l = 0; l < logK; l++)
            {

                j0 = j0 * 2 + !(compare_function(el0, treearr[j0]));
                j1 = j1 * 2 + !(compare_function(el1, treearr[j1]));
            }

            size_t b0 = j0 - k;
            size_t b1 = j1 - k;

            //TODO(an): Remove this ugly workaround as soon as emitters are movable.
            //Move emitter[actual_k] to emitter[splitter_count] before calling this.
            if (b0 >= actual_k) {
                b0 = actual_k - 1;
            }

            while (b0 && Equal(compare_function, el0, sorted_splitters[b0 - 1])
                   && (prefix_elem + i) * actual_k > b0 * total_elem) {
                b0--;
            }
            emitters[b0](el0);
            if (b1 >= actual_k) {
                b1 = actual_k - 1;
            }
            while (b1 && Equal(compare_function, el1, sorted_splitters[b1 - 1])
                   && (prefix_elem + i + 1) * actual_k > b1 * total_elem) {
                b1--;
            }
            emitters[b1](el1);
        }
        for ( ; i < n; i++)
        {

            size_t j = 1;
            for (size_t l = 0; l < logK; l++)
            {
                j = j * 2 + !(compare_function(a[i], treearr[j]));
            }
            size_t b = j - k;

            if (b >= actual_k) {
                b = actual_k - 1;
            }
            while (b && Equal(compare_function, a[i], sorted_splitters[b - 1])
                   && (prefix_elem + i) * actual_k > b * total_elem) {
                b--;
            }
            emitters[b](a[i]);
        }
    }
};

}

//! \addtogroup api Interface
//! \{

/*!
 * A DIANode which performs a Sort operation. Sort sorts a DIA according to a given
 * compare function
 *
 * \tparam ValueType Type of DIA elements
 * \tparam Stack Function stack, which contains the chained lambdas between the last and this DIANode.
 * \tparam CompareFunction Type of the compare function
 */
template <typename ValueType, typename ParentStack, typename CompareFunction>
class SortNode : public DOpNode<ValueType>
{
    static const bool debug = false;

    using Super = DOpNode<ValueType>;
    using Super::context_;
    using Super::result_file_;

    using ParentInput = typename ParentStack::Input;

public:
    /*!
     * Constructor for a sort node.
     *
     * \param ctx Context for this operation
     * \param parent Previous DIANode in the computation chain
     * \param parent_stack Stack of lambda functions between parent and this node
     * \param compare_function Function comparing two elements.
     */
    SortNode(Context& ctx,
             std::shared_ptr<DIANode<ParentInput> > parent,
             const ParentStack& parent_stack,
             CompareFunction compare_function)
        : DOpNode<ValueType>(ctx, { parent }, "Sort"),
          compare_function_(compare_function),
          channel_id_samples_(ctx.data_manager().GetNewChannel()),
          emitters_samples_(channel_id_samples_->OpenWriters()),
          channel_id_data_(ctx.data_manager().GetNewChannel()),
          emitters_data_(channel_id_data_->OpenWriters()),
          parent_(parent)
    {
        // Hook PreOp(s)
        auto pre_op_fn = [ = ](const ValueType& input) {
                             PreOp(input);
                         };

        lop_chain_ = parent_stack.push(pre_op_fn).emit();

        parent_->RegisterChild(lop_chain_);
    }

    virtual ~SortNode() {
        parent_->UnregisterChild(lop_chain_);
    }

    //! Executes the sum operation.
    void Execute() override {
        this->StartExecutionTimer();
        MainOp();
        this->StopExecutionTimer();
    }

    /*!
     * Produces an 'empty' function stack, which only contains the identity
     * emitter function.
     *
     * \return Empty function stack
     */
    auto ProduceStack() {
        // Hook Identity
        auto id_fn = [ = ](ValueType t, auto emit_func) {
                         return emit_func(t);
                     };

        return MakeFunctionStack<ValueType>(id_fn);
    }

    /*!
     * Returns "[SortNode]" as a string.
     * \return "[SortNode]"
     */
    std::string ToString() override {
        return "[SortNode] Id:" + result_file_.ToString();
    }

private:
    //! The sum function which is applied to two elements.
    CompareFunction compare_function_;
    //! Local data
    std::vector<ValueType> data_;

    //!Emitter to send samples to process 0
    data::ChannelPtr channel_id_samples_;
    std::vector<data::BlockWriter> emitters_samples_;

    //!Emitters to send data to other workers specified by splitters.
    data::ChannelPtr channel_id_data_;
    std::vector<data::BlockWriter> emitters_data_;

    //epsilon
    double desired_imbalance = 0.25;

    std::shared_ptr<DIANode<ParentInput>> parent_;
    common::delegate<void(ParentInput)> lop_chain_;

    void PreOp(ValueType input) {
        data_.push_back(input);
    }

    void FindAndSendSplitters(std::vector<ValueType>& splitters) {
        //Get samples from other workers
        size_t num_workers = context_.number_worker();
        size_t samplesize = std::ceil(log2((double)data_.size()) *
                                      (1 / (desired_imbalance *
                                            desired_imbalance)));

        std::vector<ValueType> samples;
        samples.reserve(samplesize * num_workers);
        auto reader = channel_id_samples_->OpenReader();

        while (reader.HasNext()) {
            samples.push_back(reader.template Next<ValueType>());
        }

        //Find splitters
        std::sort(samples.begin(), samples.end(), compare_function_);

        size_t splitting_size = samples.size() / num_workers;

        //Send splitters to other workers
        for (size_t i = 1; i < num_workers; i++) {
            splitters.push_back(samples[i * splitting_size]);
            for (size_t j = 1; j < num_workers; j++) {
                emitters_samples_[j](samples[i * splitting_size]);
            }
        }

        for (size_t j = 1; j < num_workers; j++) {
            emitters_samples_[j].Close();
        }
    }

    void MainOp() {
        net::FlowControlChannel& channel = context_.flow_control_channel();

        size_t prefix_elem = channel.PrefixSum(data_.size());
        size_t total_elem = channel.AllReduce(data_.size());

        size_t num_workers = context_.number_worker();
        size_t samplesize = std::ceil(log2((double)total_elem) *
                                      (1 / (desired_imbalance * desired_imbalance)));

        LOG << prefix_elem << " elements, out of " << total_elem;

        std::random_device random_device;
        std::default_random_engine generator(random_device());
        std::uniform_int_distribution<int> distribution(0, data_.size() - 1);

        //Send samples to worker 0
        for (size_t i = 0; i < samplesize; i++) {
            size_t sample = distribution(generator);
            emitters_samples_[0](data_[sample]);
        }
        emitters_samples_[0].Close();

        //Get the ceiling of log(num_workers), as SSSS needs 2^n buckets.
        double log_workers = std::log2(num_workers);
        const bool powof2 = (std::ceil(log_workers) - log_workers) < 0.0000001;
        size_t ceil_log = std::ceil(log_workers);
        size_t workers_algo = 1 << ceil_log;
        size_t splitter_count_algo = workers_algo - 1;

        std::vector<ValueType> splitters;
        splitters.reserve(workers_algo);

        if (context_.rank() == 0) {
            FindAndSendSplitters(splitters);
        }
        else {
            //Close unused emitters
            for (size_t j = 1; j < num_workers; j++) {
                emitters_samples_[j].Close();
            }
            auto reader = channel_id_samples_->OpenReader();
            while (reader.HasNext()) {
                splitters.push_back(reader.template Next<ValueType>());
            }
        }

        //code from SS2NPartition, slightly altered

        ValueType* splitter_tree = new ValueType[workers_algo + 1];

        if (!powof2) {
            for (size_t i = num_workers; i < workers_algo; i++) {
                splitters.push_back(splitters.back());
            }
        }

        TreeBuilder<ValueType>(splitter_tree,
                                     splitters.data(),
                                     splitter_count_algo);

        BucketEmitter<ValueType, CompareFunction>::emitToBuckets(
            data_.data(),
            data_.size(),
            splitter_tree, // Tree. sizeof |splitter|
            workers_algo,  // Number of buckets
            ceil_log,
            emitters_data_,
            num_workers,
            compare_function_,
            splitters.data(),
            prefix_elem,
            total_elem);

        //end of SS2N

        for (size_t i = 0; i < emitters_data_.size(); i++) {
            emitters_data_[i].Close();
        }

        data_.clear();

        auto reader = channel_id_data_->OpenReader();

        while (reader.HasNext()) {
            data_.push_back(reader.template Next<ValueType>());
        }

		LOG << "node " << context_.rank() << " : " << data_.size();

        std::sort(data_.begin(), data_.end(), compare_function_);

        for (size_t i = 0; i < data_.size(); i++) {
            for (auto func : DIANode<ValueType>::callbacks_) {
                func(data_[i]);
            }
        }
        std::vector<ValueType>().swap(data_);
    }

    void PostOp() { }
};

template <typename ValueType, typename Stack>
template <typename CompareFunction>
auto DIARef<ValueType, Stack>::Sort(const CompareFunction &compare_function) const {

    using SortResultNode
              = SortNode<ValueType, Stack, CompareFunction>;

    static_assert(
        std::is_same<
            typename common::FunctionTraits<CompareFunction>::template arg<0>,
            ValueType>::value ||
        std::is_same<CompareFunction, std::less<ValueType> >::value,
        "CompareFunction has the wrong input type");

    static_assert(
        std::is_same<
            typename common::FunctionTraits<CompareFunction>::template arg<1>,
            ValueType>::value ||
        std::is_same<CompareFunction, std::less<ValueType> >::value,
        "CompareFunction has the wrong input type");

    static_assert(
        std::is_same<
            typename common::FunctionTraits<CompareFunction>::result_type,
            bool>::value ||
        std::is_same<CompareFunction, std::less<ValueType> >::value,
        "CompareFunction has the wrong output type (should be bool)");

    auto shared_node
        = std::make_shared<SortResultNode>(node_->context(),
                                           node_,
                                           stack_,
                                           compare_function);

    auto sort_stack = shared_node->ProduceStack();

    return DIARef<ValueType, decltype(sort_stack)>(
        std::move(shared_node), sort_stack);
}

//! \}
} // namespace api
} // namespace c7a

#endif // !C7A_API_SORT_HEADER

/******************************************************************************/
<commit_msg>Simplifying sort treebuilder.<commit_after>/*******************************************************************************
 * c7a/api/sort.hpp
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Alexander Noe <aleexnoe@gmail.com>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_API_SORT_HEADER
#define C7A_API_SORT_HEADER

#include <c7a/api/context.hpp>
#include <c7a/api/dia.hpp>
#include <c7a/api/function_stack.hpp>
#include <c7a/common/logger.hpp>
#include <c7a/net/collective_communication.hpp>
#include <c7a/net/flow_control_channel.hpp>
#include <c7a/net/flow_control_manager.hpp>
#include <c7a/net/group.hpp>

#include <cmath>

namespace c7a {
namespace api {

//! \addtogroup api Interface
//! \{

namespace sort_local {

template <typename ValueType>
struct TreeBuilder
{
    ValueType * tree_;
    ValueType * samples_;
    size_t    index_ = 0;
    size_t    ssplitter;

    /*!
     * Target: tree. Size of 'number of splitter'
     * Source: sorted splitters. Size of 'number of splitter'
     * Number of splitter
     */
    TreeBuilder(ValueType* splitter_tree,
                ValueType* samples,
                size_t ssplitter)
        : tree_(splitter_tree),
          samples_(samples),
          ssplitter(ssplitter) {
        recurse(samples, samples + ssplitter, 1);
    }

    void recurse(ValueType* lo, ValueType* hi, unsigned int treeidx) {

        // pick middle element as splitter
        ValueType* mid = lo + (ssize_t)(hi - lo) / 2;
        tree_[treeidx] = *mid;

        ValueType* midlo = mid, * midhi = mid + 1;

        if (2 * treeidx < ssplitter)
        {
            recurse(lo, midlo, 2 * treeidx + 0);
            recurse(midhi, hi, 2 * treeidx + 1);
        }
    }
};

template <class T1, typename CompareFunction>
struct BucketEmitter
{
    static bool Equal(CompareFunction compare_function, const T1& ele1, const T1& ele2) {
        return !(compare_function(ele1, ele2) || compare_function(ele2, ele1));
    }

        static size_t RoundDown(size_t ele, size_t by) {
                return ((ele) & ~((by) - 1));
        }

    static void emitToBuckets(
        const T1* const a,
        const size_t n,
        const T1* const treearr, // Tree. sizeof |splitter|
        size_t k,                // Number of buckets
        size_t logK,
        std::vector<data::BlockWriter>& emitters,
        size_t actual_k,
        CompareFunction compare_function,
        const T1* const sorted_splitters,
        size_t prefix_elem,
        size_t total_elem) {

        const size_t stepsize = 2;

        size_t i = 0;
        for ( ; i < RoundDown(n, stepsize); i += stepsize)
        {

            size_t j0 = 1;
            const T1& el0 = a[i];
            size_t j1 = 1;
            const T1& el1 = a[i + 1];

            for (size_t l = 0; l < logK; l++)
            {

                j0 = j0 * 2 + !(compare_function(el0, treearr[j0]));
                j1 = j1 * 2 + !(compare_function(el1, treearr[j1]));
            }

            size_t b0 = j0 - k;
            size_t b1 = j1 - k;

            //TODO(an): Remove this ugly workaround as soon as emitters are movable.
            //Move emitter[actual_k] to emitter[splitter_count] before calling this.
            if (b0 >= actual_k) {
                b0 = actual_k - 1;
            }

            while (b0 && Equal(compare_function, el0, sorted_splitters[b0 - 1])
                   && (prefix_elem + i) * actual_k > b0 * total_elem) {
                b0--;
            }
            emitters[b0](el0);
            if (b1 >= actual_k) {
                b1 = actual_k - 1;
            }
            while (b1 && Equal(compare_function, el1, sorted_splitters[b1 - 1])
                   && (prefix_elem + i + 1) * actual_k > b1 * total_elem) {
                b1--;
            }
            emitters[b1](el1);
        }
        for ( ; i < n; i++)
        {

            size_t j = 1;
            for (size_t l = 0; l < logK; l++)
            {
                j = j * 2 + !(compare_function(a[i], treearr[j]));
            }
            size_t b = j - k;

            if (b >= actual_k) {
                b = actual_k - 1;
            }
            while (b && Equal(compare_function, a[i], sorted_splitters[b - 1])
                   && (prefix_elem + i) * actual_k > b * total_elem) {
                b--;
            }
            emitters[b](a[i]);
        }
    }
};

} // namespace sort_local

/*!
 * A DIANode which performs a Sort operation. Sort sorts a DIA according to a given
 * compare function
 *
 * \tparam ValueType Type of DIA elements
 * \tparam Stack Function stack, which contains the chained lambdas between the last and this DIANode.
 * \tparam CompareFunction Type of the compare function
 */
template <typename ValueType, typename ParentStack, typename CompareFunction>
class SortNode : public DOpNode<ValueType>
{
    static const bool debug = false;

    using Super = DOpNode<ValueType>;
    using Super::context_;
    using Super::result_file_;

    using ParentInput = typename ParentStack::Input;

public:
    /*!
     * Constructor for a sort node.
     *
     * \param ctx Context for this operation
     * \param parent Previous DIANode in the computation chain
     * \param parent_stack Stack of lambda functions between parent and this node
     * \param compare_function Function comparing two elements.
     */
    SortNode(Context& ctx,
             std::shared_ptr<DIANode<ParentInput> > parent,
             const ParentStack& parent_stack,
             CompareFunction compare_function)
        : DOpNode<ValueType>(ctx, { parent }, "Sort"),
          compare_function_(compare_function),
          channel_id_samples_(ctx.data_manager().GetNewChannel()),
          emitters_samples_(channel_id_samples_->OpenWriters()),
          channel_id_data_(ctx.data_manager().GetNewChannel()),
          emitters_data_(channel_id_data_->OpenWriters()),
          parent_(parent)
    {
        // Hook PreOp(s)
        auto pre_op_fn = [ = ](const ValueType& input) {
                             PreOp(input);
                         };

        lop_chain_ = parent_stack.push(pre_op_fn).emit();

        parent_->RegisterChild(lop_chain_);
    }

    virtual ~SortNode() {
        parent_->UnregisterChild(lop_chain_);
    }

    //! Executes the sum operation.
    void Execute() override {
        this->StartExecutionTimer();
        MainOp();
        this->StopExecutionTimer();
    }

    /*!
     * Produces an 'empty' function stack, which only contains the identity
     * emitter function.
     *
     * \return Empty function stack
     */
    auto ProduceStack() {
        // Hook Identity
        auto id_fn = [ = ](ValueType t, auto emit_func) {
                         return emit_func(t);
                     };

        return MakeFunctionStack<ValueType>(id_fn);
    }

    /*!
     * Returns "[SortNode]" as a string.
     * \return "[SortNode]"
     */
    std::string ToString() override {
        return "[SortNode] Id:" + result_file_.ToString();
    }

private:
    //! The sum function which is applied to two elements.
    CompareFunction compare_function_;
    //! Local data
    std::vector<ValueType> data_;

    //!Emitter to send samples to process 0
    data::ChannelPtr channel_id_samples_;
    std::vector<data::BlockWriter> emitters_samples_;

    //!Emitters to send data to other workers specified by splitters.
    data::ChannelPtr channel_id_data_;
    std::vector<data::BlockWriter> emitters_data_;

    //epsilon
    double desired_imbalance = 0.25;

    std::shared_ptr<DIANode<ParentInput>> parent_;
    common::delegate<void(ParentInput)> lop_chain_;

    void PreOp(ValueType input) {
        data_.push_back(input);
    }

    void FindAndSendSplitters(std::vector<ValueType>& splitters) {
        //Get samples from other workers
        size_t num_workers = context_.number_worker();
        size_t samplesize = std::ceil(log2((double)data_.size()) *
                                      (1 / (desired_imbalance *
                                            desired_imbalance)));

        std::vector<ValueType> samples;
        samples.reserve(samplesize * num_workers);
        auto reader = channel_id_samples_->OpenReader();

        while (reader.HasNext()) {
            samples.push_back(reader.template Next<ValueType>());
        }

        //Find splitters
        std::sort(samples.begin(), samples.end(), compare_function_);

        size_t splitting_size = samples.size() / num_workers;

        //Send splitters to other workers
        for (size_t i = 1; i < num_workers; i++) {
            splitters.push_back(samples[i * splitting_size]);
            for (size_t j = 1; j < num_workers; j++) {
                emitters_samples_[j](samples[i * splitting_size]);
            }
        }

        for (size_t j = 1; j < num_workers; j++) {
            emitters_samples_[j].Close();
        }
    }

    void MainOp() {
        net::FlowControlChannel& channel = context_.flow_control_channel();

        size_t prefix_elem = channel.PrefixSum(data_.size());
        size_t total_elem = channel.AllReduce(data_.size());

        size_t num_workers = context_.number_worker();
        size_t samplesize = std::ceil(log2((double)total_elem) *
                                      (1 / (desired_imbalance * desired_imbalance)));

        LOG << prefix_elem << " elements, out of " << total_elem;

        std::random_device random_device;
        std::default_random_engine generator(random_device());
        std::uniform_int_distribution<int> distribution(0, data_.size() - 1);

        //Send samples to worker 0
        for (size_t i = 0; i < samplesize; i++) {
            size_t sample = distribution(generator);
            emitters_samples_[0](data_[sample]);
        }
        emitters_samples_[0].Close();

        //Get the ceiling of log(num_workers), as SSSS needs 2^n buckets.
        double log_workers = std::log2(num_workers);
        const bool powof2 = (std::ceil(log_workers) - log_workers) < 0.0000001;
        size_t ceil_log = std::ceil(log_workers);
        size_t workers_algo = 1 << ceil_log;
        size_t splitter_count_algo = workers_algo - 1;

        std::vector<ValueType> splitters;
        splitters.reserve(workers_algo);

        if (context_.rank() == 0) {
            FindAndSendSplitters(splitters);
        }
        else {
            //Close unused emitters
            for (size_t j = 1; j < num_workers; j++) {
                emitters_samples_[j].Close();
            }
            auto reader = channel_id_samples_->OpenReader();
            while (reader.HasNext()) {
                splitters.push_back(reader.template Next<ValueType>());
            }
        }

        //code from SS2NPartition, slightly altered

        ValueType* splitter_tree = new ValueType[workers_algo + 1];

        if (!powof2) {
            for (size_t i = num_workers; i < workers_algo; i++) {
                splitters.push_back(splitters.back());
            }
        }

        sort_local::TreeBuilder<ValueType>(splitter_tree,
                                     splitters.data(),
                                     splitter_count_algo);

        sort_local::BucketEmitter<ValueType, CompareFunction>::emitToBuckets(
            data_.data(),
            data_.size(),
            splitter_tree, // Tree. sizeof |splitter|
            workers_algo,  // Number of buckets
            ceil_log,
            emitters_data_,
            num_workers,
            compare_function_,
            splitters.data(),
            prefix_elem,
            total_elem);

        //end of SS2N

        for (size_t i = 0; i < emitters_data_.size(); i++) {
            emitters_data_[i].Close();
        }

        data_.clear();

        auto reader = channel_id_data_->OpenReader();

        while (reader.HasNext()) {
            data_.push_back(reader.template Next<ValueType>());
        }

                LOG << "node " << context_.rank() << " : " << data_.size();

        std::sort(data_.begin(), data_.end(), compare_function_);

        for (size_t i = 0; i < data_.size(); i++) {
            for (auto func : DIANode<ValueType>::callbacks_) {
                func(data_[i]);
            }
        }
        std::vector<ValueType>().swap(data_);
    }

    void PostOp() { }
};

template <typename ValueType, typename Stack>
template <typename CompareFunction>
auto DIARef<ValueType, Stack>::Sort(const CompareFunction &compare_function) const {

    using SortResultNode
              = SortNode<ValueType, Stack, CompareFunction>;

    static_assert(
        std::is_same<
            typename common::FunctionTraits<CompareFunction>::template arg<0>,
            ValueType>::value ||
        std::is_same<CompareFunction, std::less<ValueType> >::value,
        "CompareFunction has the wrong input type");

    static_assert(
        std::is_same<
            typename common::FunctionTraits<CompareFunction>::template arg<1>,
            ValueType>::value ||
        std::is_same<CompareFunction, std::less<ValueType> >::value,
        "CompareFunction has the wrong input type");

    static_assert(
        std::is_same<
            typename common::FunctionTraits<CompareFunction>::result_type,
            bool>::value ||
        std::is_same<CompareFunction, std::less<ValueType> >::value,
        "CompareFunction has the wrong output type (should be bool)");

    auto shared_node
        = std::make_shared<SortResultNode>(node_->context(),
                                           node_,
                                           stack_,
                                           compare_function);

    auto sort_stack = shared_node->ProduceStack();

    return DIARef<ValueType, decltype(sort_stack)>(
        std::move(shared_node), sort_stack);
}

//! \}
} // namespace api
} // namespace c7a

#endif // !C7A_API_SORT_HEADER

/******************************************************************************/
<|endoftext|>


<commit_before>/*
  This file is part of the Grantlee template system.

  Copyright (c) 2009,2010 Stephen Kelly <steveire@gmail.com>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either version
  2.1 of the Licence, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "parser.h"

#include "engine.h"
#include "exception.h"
#include "filter.h"
#include "grantlee_version.h"
#include "nodebuiltins_p.h"
#include "taglibraryinterface.h"
#include "template.h"
#include "template_p.h"

#include <QtCore/QFile>

using namespace Grantlee;

namespace Grantlee
{

class ParserPrivate
{
public:
  ParserPrivate( Parser *parser, const QList<Token> &tokenList )
      : q_ptr( parser ),
      m_tokenList( tokenList ) {

  }

  NodeList extendNodeList( NodeList list, Node *node );

  /**
    Parses the template to create a Nodelist.
    The given @p parent is the parent of each node in the returned list.
  */
  NodeList parse( QObject *parent, const QStringList &stopAt = QStringList() );

  void openLibrary( TagLibraryInterface * library );
  Q_DECLARE_PUBLIC( Parser )
  Parser * const q_ptr;

  QList<Token> m_tokenList;

  QHash<QString, AbstractNodeFactory*> m_nodeFactories;
  QHash<QString, Filter::Ptr> m_filters;

  NodeList m_nodeList;
};

}

void ParserPrivate::openLibrary( TagLibraryInterface *library )
{
  Q_Q( Parser );
  QHashIterator<QString, AbstractNodeFactory*> nodeIt( library->nodeFactories() );

  TemplateImpl *ti = qobject_cast<TemplateImpl *>( q->parent() );

  Engine const *cengine = ti->engine();
  if ( !cengine )
    return;
  Engine *engine = const_cast<Engine *>( cengine );

  while ( nodeIt.hasNext() ) {
    nodeIt.next();
    nodeIt.value()->setEngine( engine );
    m_nodeFactories.insert( nodeIt.key(), nodeIt.value() );
  }
  QHashIterator<QString, Filter*> filterIt( library->filters() );
  while ( filterIt.hasNext() ) {
    filterIt.next();
    Filter::Ptr f = Filter::Ptr( filterIt.value() );
    m_filters.insert( filterIt.key(), f );
  }
}

Parser::Parser( const QList<Token> &tokenList, QObject *parent )
    : QObject( parent ), d_ptr( new ParserPrivate( this, tokenList ) )
{
  Q_D( Parser );

  TemplateImpl *ti = qobject_cast<TemplateImpl *>( parent );

  Engine const *cengine = ti->engine();
  if ( !cengine )
    return;
  Engine *engine = const_cast<Engine *>( cengine );
  engine->loadDefaultLibraries();
  Q_FOREACH( const QString &libraryName, engine->defaultLibraries() ) {
    TagLibraryInterface *library = engine->loadLibrary( libraryName );
    if ( !library )
      continue;
    d->openLibrary( library );
  }
}

Parser::~Parser()
{
  // Don't delete filters here because filters must out-live the parser in the
  // filter expressions.
  qDeleteAll( d_ptr->m_nodeFactories );
  delete d_ptr;
}

void Parser::setTokens( const QList< Token >& tokenList )
{
  Q_D( Parser );
  d->m_tokenList = tokenList;
}

void Parser::loadLib( const QString &name )
{
  Q_D( Parser );
  TemplateImpl *ti = qobject_cast<TemplateImpl *>( parent() );
  Engine const *cengine = ti->engine();
  if ( !cengine )
    return;
  Engine *engine = const_cast<Engine *>( cengine );
  TagLibraryInterface *library = engine->loadLibrary( name );
  if ( !library )
    return;
  d->openLibrary( library );
}

NodeList ParserPrivate::extendNodeList( NodeList list, Node *node )
{
  if ( node->mustBeFirst() && list.containsNonText() ) {
    throw Grantlee::Exception( TagSyntaxError, QString::fromLatin1(
        "Node appeared twice in template: %1" ).arg( QLatin1String( node->metaObject()->className() ) ) );
  }

  list.append( node );
  return list;
}

void Parser::skipPast( const QString &tag )
{
  while ( hasNextToken() ) {
    const Token token = takeNextToken();
    if ( token.tokenType == BlockToken && token.content.trimmed() == tag )
      return;
  }
  throw Grantlee::Exception( UnclosedBlockTagError, QString::fromLatin1( "No closing tag found for %1" ).arg( tag ) );
}

Filter::Ptr Parser::getFilter( const QString &name ) const
{
  Q_D( const Parser );
  if ( !d->m_filters.contains( name ) )
    throw Grantlee::Exception( UnknownFilterError, QString::fromLatin1( "Unknown filter: %1" ).arg( name ) );
  return d->m_filters.value( name );
}

NodeList Parser::parse( Node *parent, const QString &stopAt )
{
  Q_D( Parser );
  return d->parse( parent, QStringList() << stopAt );
}

NodeList Parser::parse( TemplateImpl *parent, const QStringList &stopAt )
{
  Q_D( Parser );
  return d->parse( parent, stopAt );
}

NodeList Parser::parse( Node *parent, const QStringList &stopAt )
{
  Q_D( Parser );
  return d->parse( parent, stopAt );
}

NodeList ParserPrivate::parse( QObject *parent, const QStringList &stopAt )
{
  Q_Q( Parser );
  NodeList nodeList;

  while ( q->hasNextToken() ) {
    const Token token = q->takeNextToken();
    if ( token.tokenType == TextToken ) {
      nodeList = extendNodeList( nodeList, new TextNode( token.content, parent ) );
    } else if ( token.tokenType == VariableToken ) {
      if ( token.content.isEmpty() ) {
        // Error. Empty variable
        QString message;
        message = QString::fromLatin1( "Empty variable before \"%1\", line %2, %3" ).arg( q->takeNextToken().content.left( 20 ) ).arg( token.linenumber ).arg( q->parent()->objectName() );
        throw Grantlee::Exception( EmptyVariableError, message );
      }

      FilterExpression filterExpression;
      try {
        filterExpression = FilterExpression( token.content, q );
      } catch ( Grantlee::Exception e ) {
        throw Grantlee::Exception( e.errorCode(), QString::fromLatin1( "%1, line %2, %3" ).arg( e.what() )
                                                                              .arg( token.linenumber )
                                                                              .arg( q->parent()->objectName() ) );
      }

      nodeList = extendNodeList( nodeList, new VariableNode( filterExpression, parent ) );
    } else {
      Q_ASSERT( token.tokenType == BlockToken );
      if ( stopAt.contains( token.content ) ) {
        // put the token back.
        q->prependToken( token );
        return nodeList;
      }

      const QStringList tagContents = token.content.split( QLatin1Char( ' ' ) );
      if ( tagContents.size() == 0 ) {
        QString message;
        if ( q->hasNextToken() )
          message = QString::fromLatin1( "Empty block tag before \"%1\", line %2, %3" ).arg( token.content.left( 20 ) ).arg( token.linenumber ).arg( q->parent()->objectName() );
        else
          message = QLatin1String( "Empty block tag at end of input." );

        throw Grantlee::Exception( EmptyBlockTagError, message );
      }
      const QString command = tagContents.first();
      AbstractNodeFactory *nodeFactory = m_nodeFactories[command];

      // unknown tag.
      if ( !nodeFactory ) {
        throw Grantlee::Exception( InvalidBlockTagError, QString::fromLatin1( "Unknown tag: \"%1\", line %2, %3" ).arg( command ).arg( token.linenumber ).arg( q->parent()->objectName() ) );
      }

      // TODO: Make getNode take a Token instead?
      Node *n;
      try {
        n = nodeFactory->getNode( token.content, q );
      } catch ( Grantlee::Exception e ) {
        throw Grantlee::Exception( e.errorCode(), QString::fromLatin1( "%1, line %2, %3" ).arg( e.what() )
                                                                              .arg( token.linenumber )
                                                                              .arg( q->parent()->objectName() ) );
      }
      if ( !n ) {
        throw Grantlee::Exception( EmptyBlockTagError, QString::fromLatin1( "Failed to get node from %1, line %2, %3" ).arg( command ).arg( token.linenumber ).arg( q->parent()->objectName() ) );
      }

      n->setParent( parent );

      nodeList = extendNodeList( nodeList, n );
    }
  }

  if ( !stopAt.isEmpty() ) {
    const QString message = QString::fromLatin1( "Unclosed tag in template %1. Expected one of: (%2)" ).arg( q->parent()->objectName() ).arg( stopAt.join( QChar::fromLatin1( ' ' ) ) );
    throw Grantlee::Exception( UnclosedBlockTagError, message );
  }

  return nodeList;

}

bool Parser::hasNextToken() const
{
  Q_D( const Parser );
  return !d->m_tokenList.isEmpty();
}

Token Parser::takeNextToken()
{
  Q_D( Parser );
  return d->m_tokenList.takeFirst();
}

void Parser::removeNextToken()
{
  Q_D( Parser );
  if ( !d->m_tokenList.isEmpty() )
    d->m_tokenList.removeFirst();;
}

void Parser::prependToken( const Token &token )
{
  Q_D( Parser );
  d->m_tokenList.prepend( token );
}

#include "parser.moc"

<commit_msg>Remove dead code. The parser must be a child of the engine.<commit_after>/*
  This file is part of the Grantlee template system.

  Copyright (c) 2009,2010 Stephen Kelly <steveire@gmail.com>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either version
  2.1 of the Licence, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "parser.h"

#include "engine.h"
#include "exception.h"
#include "filter.h"
#include "grantlee_version.h"
#include "nodebuiltins_p.h"
#include "taglibraryinterface.h"
#include "template.h"
#include "template_p.h"

#include <QtCore/QFile>

using namespace Grantlee;

namespace Grantlee
{

class ParserPrivate
{
public:
  ParserPrivate( Parser *parser, const QList<Token> &tokenList )
      : q_ptr( parser ),
      m_tokenList( tokenList ) {

  }

  NodeList extendNodeList( NodeList list, Node *node );

  /**
    Parses the template to create a Nodelist.
    The given @p parent is the parent of each node in the returned list.
  */
  NodeList parse( QObject *parent, const QStringList &stopAt = QStringList() );

  void openLibrary( TagLibraryInterface * library );
  Q_DECLARE_PUBLIC( Parser )
  Parser * const q_ptr;

  QList<Token> m_tokenList;

  QHash<QString, AbstractNodeFactory*> m_nodeFactories;
  QHash<QString, Filter::Ptr> m_filters;

  NodeList m_nodeList;
};

}

void ParserPrivate::openLibrary( TagLibraryInterface *library )
{
  Q_Q( Parser );
  QHashIterator<QString, AbstractNodeFactory*> nodeIt( library->nodeFactories() );

  TemplateImpl *ti = qobject_cast<TemplateImpl *>( q->parent() );

  Engine const *cengine = ti->engine();
  Q_ASSERT( cengine );
  Engine *engine = const_cast<Engine *>( cengine );

  while ( nodeIt.hasNext() ) {
    nodeIt.next();
    nodeIt.value()->setEngine( engine );
    m_nodeFactories.insert( nodeIt.key(), nodeIt.value() );
  }
  QHashIterator<QString, Filter*> filterIt( library->filters() );
  while ( filterIt.hasNext() ) {
    filterIt.next();
    Filter::Ptr f = Filter::Ptr( filterIt.value() );
    m_filters.insert( filterIt.key(), f );
  }
}

Parser::Parser( const QList<Token> &tokenList, QObject *parent )
    : QObject( parent ), d_ptr( new ParserPrivate( this, tokenList ) )
{
  Q_D( Parser );

  TemplateImpl *ti = qobject_cast<TemplateImpl *>( parent );

  Engine const *cengine = ti->engine();
  Q_ASSERT( cengine );

  Engine *engine = const_cast<Engine *>( cengine );
  engine->loadDefaultLibraries();
  Q_FOREACH( const QString &libraryName, engine->defaultLibraries() ) {
    TagLibraryInterface *library = engine->loadLibrary( libraryName );
    if ( !library )
      continue;
    d->openLibrary( library );
  }
}

Parser::~Parser()
{
  // Don't delete filters here because filters must out-live the parser in the
  // filter expressions.
  qDeleteAll( d_ptr->m_nodeFactories );
  delete d_ptr;
}

void Parser::setTokens( const QList< Token >& tokenList )
{
  Q_D( Parser );
  d->m_tokenList = tokenList;
}

void Parser::loadLib( const QString &name )
{
  Q_D( Parser );
  TemplateImpl *ti = qobject_cast<TemplateImpl *>( parent() );
  Engine const *cengine = ti->engine();
  Q_ASSERT( cengine );
  Engine *engine = const_cast<Engine *>( cengine );
  TagLibraryInterface *library = engine->loadLibrary( name );
  if ( !library )
    return;
  d->openLibrary( library );
}

NodeList ParserPrivate::extendNodeList( NodeList list, Node *node )
{
  if ( node->mustBeFirst() && list.containsNonText() ) {
    throw Grantlee::Exception( TagSyntaxError, QString::fromLatin1(
        "Node appeared twice in template: %1" ).arg( QLatin1String( node->metaObject()->className() ) ) );
  }

  list.append( node );
  return list;
}

void Parser::skipPast( const QString &tag )
{
  while ( hasNextToken() ) {
    const Token token = takeNextToken();
    if ( token.tokenType == BlockToken && token.content.trimmed() == tag )
      return;
  }
  throw Grantlee::Exception( UnclosedBlockTagError, QString::fromLatin1( "No closing tag found for %1" ).arg( tag ) );
}

Filter::Ptr Parser::getFilter( const QString &name ) const
{
  Q_D( const Parser );
  if ( !d->m_filters.contains( name ) )
    throw Grantlee::Exception( UnknownFilterError, QString::fromLatin1( "Unknown filter: %1" ).arg( name ) );
  return d->m_filters.value( name );
}

NodeList Parser::parse( Node *parent, const QString &stopAt )
{
  Q_D( Parser );
  return d->parse( parent, QStringList() << stopAt );
}

NodeList Parser::parse( TemplateImpl *parent, const QStringList &stopAt )
{
  Q_D( Parser );
  return d->parse( parent, stopAt );
}

NodeList Parser::parse( Node *parent, const QStringList &stopAt )
{
  Q_D( Parser );
  return d->parse( parent, stopAt );
}

NodeList ParserPrivate::parse( QObject *parent, const QStringList &stopAt )
{
  Q_Q( Parser );
  NodeList nodeList;

  while ( q->hasNextToken() ) {
    const Token token = q->takeNextToken();
    if ( token.tokenType == TextToken ) {
      nodeList = extendNodeList( nodeList, new TextNode( token.content, parent ) );
    } else if ( token.tokenType == VariableToken ) {
      if ( token.content.isEmpty() ) {
        // Error. Empty variable
        QString message;
        message = QString::fromLatin1( "Empty variable before \"%1\", line %2, %3" ).arg( q->takeNextToken().content.left( 20 ) ).arg( token.linenumber ).arg( q->parent()->objectName() );
        throw Grantlee::Exception( EmptyVariableError, message );
      }

      FilterExpression filterExpression;
      try {
        filterExpression = FilterExpression( token.content, q );
      } catch ( Grantlee::Exception e ) {
        throw Grantlee::Exception( e.errorCode(), QString::fromLatin1( "%1, line %2, %3" ).arg( e.what() )
                                                                              .arg( token.linenumber )
                                                                              .arg( q->parent()->objectName() ) );
      }

      nodeList = extendNodeList( nodeList, new VariableNode( filterExpression, parent ) );
    } else {
      Q_ASSERT( token.tokenType == BlockToken );
      if ( stopAt.contains( token.content ) ) {
        // put the token back.
        q->prependToken( token );
        return nodeList;
      }

      const QStringList tagContents = token.content.split( QLatin1Char( ' ' ) );
      if ( tagContents.size() == 0 ) {
        QString message;
        if ( q->hasNextToken() )
          message = QString::fromLatin1( "Empty block tag before \"%1\", line %2, %3" ).arg( token.content.left( 20 ) ).arg( token.linenumber ).arg( q->parent()->objectName() );
        else
          message = QLatin1String( "Empty block tag at end of input." );

        throw Grantlee::Exception( EmptyBlockTagError, message );
      }
      const QString command = tagContents.first();
      AbstractNodeFactory *nodeFactory = m_nodeFactories[command];

      // unknown tag.
      if ( !nodeFactory ) {
        throw Grantlee::Exception( InvalidBlockTagError, QString::fromLatin1( "Unknown tag: \"%1\", line %2, %3" ).arg( command ).arg( token.linenumber ).arg( q->parent()->objectName() ) );
      }

      // TODO: Make getNode take a Token instead?
      Node *n;
      try {
        n = nodeFactory->getNode( token.content, q );
      } catch ( Grantlee::Exception e ) {
        throw Grantlee::Exception( e.errorCode(), QString::fromLatin1( "%1, line %2, %3" ).arg( e.what() )
                                                                              .arg( token.linenumber )
                                                                              .arg( q->parent()->objectName() ) );
      }
      if ( !n ) {
        throw Grantlee::Exception( EmptyBlockTagError, QString::fromLatin1( "Failed to get node from %1, line %2, %3" ).arg( command ).arg( token.linenumber ).arg( q->parent()->objectName() ) );
      }

      n->setParent( parent );

      nodeList = extendNodeList( nodeList, n );
    }
  }

  if ( !stopAt.isEmpty() ) {
    const QString message = QString::fromLatin1( "Unclosed tag in template %1. Expected one of: (%2)" ).arg( q->parent()->objectName() ).arg( stopAt.join( QChar::fromLatin1( ' ' ) ) );
    throw Grantlee::Exception( UnclosedBlockTagError, message );
  }

  return nodeList;

}

bool Parser::hasNextToken() const
{
  Q_D( const Parser );
  return !d->m_tokenList.isEmpty();
}

Token Parser::takeNextToken()
{
  Q_D( Parser );
  return d->m_tokenList.takeFirst();
}

void Parser::removeNextToken()
{
  Q_D( Parser );
  if ( !d->m_tokenList.isEmpty() )
    d->m_tokenList.removeFirst();;
}

void Parser::prependToken( const Token &token )
{
  Q_D( Parser );
  d->m_tokenList.prepend( token );
}

#include "parser.moc"

<|endoftext|>


<commit_before>//
//  calcPWP.cpp
//
//
//  Created by Evan McCartney-Melstad on 1/10/15.
//
//

#include "calcPWP.h"
#include <iostream>
#include <vector>
#include <fstream>
#include <thread>
#include <string>

int calcPWPfromBinaryFile (std::string binaryFile, unsigned long long int numLoci, const int numIndividuals, std::string outFile, int numThreads) {

    //****MODIFY THIS TO ONLY READ IN N LOCI AT A TIME, INSTEAD OF USING THE ENTIRE FILE****

    std::cout << "Number of threads: " << numThreads << std::endl;
    std::streampos size;
    std::ifstream file (binaryFile, std::ios::in|std::ios::binary|std::ios::ate);
    //ifstream file ("test500k.binary8bitunsigned", ios::in|ios::binary|ios::ate);
    if (file.is_open()) {
        size = file.tellg(); // Just a variable that shows position of stream--at end since ios::ate, so it's the file size. PROBABLY WON'T WORK FOR FILES LARGER THAN ~ 2GB!
        file.seekg (0, std::ios::beg); // Go back to the beginning of the file
        //file.read((char*)readCounts, size); // cast to a char* to give to file.read

        //unsigned char* readCounts;
        //readCounts = new unsigned char[size];
        std::vector<unsigned char> readCounts(size);
        file.read((char*) &readCounts[0], size);
        file.close();

        std::cout << "the entire file content is in memory" << std::endl;
        std::cout << "the total size of the file is " << size << std::endl;
        std::cout << "the number of elements in the readCounts vector is: " << readCounts.size() << std::endl; // Will give the total size bytes divided by the size of one element--so it gives the number of elements

        /* We are going to split the loci between numThreads threads. Each thread will modify two multidimensional
         vectors of the forms std::vector< std::vector<long double> > pwp(numIndividuals, std::vector<long double>(numIndividuals,0))    and   std::vector< std::vector<unsigned long long int> > weightings(numIndividuals, std::vector<unsigned long long int>(numIndividuals,0))

         First, we'll generate all of these vectors, which apparently in C++ needs to be constructed of a
         vector of two-dimensional vectors...
         */
        std::vector<std::vector<std::vector<long double>>> pwpThreads(numThreads, std::vector<std::vector<long double>> (numIndividuals, std::vector<long double> (numIndividuals,0) ) ); //pwpThreads[0] is the first 2D array for the first thread, etc...
        std::vector<std::vector<std::vector<unsigned long long int>>> weightingsThreads(numThreads, std::vector<std::vector<unsigned long long int> > (numIndividuals, std::vector<unsigned long long int> (numIndividuals,0) ) );

        std::cout << "Initialized the 3d vectors" << std::endl;

        // Now we need to determine how many loci for each thread. If we want to use the entire binary file, instead of numLoci loci, then change this to lociPerThread = (size/(numIndividuals*2))/numThreads
        //unsigned long long int lociPerThread = numLoci / numThreads;

        //unsigned long long int lociPerThread = (readCounts.size()-1)/numThreads; // loci starts with 0, so need to subtract 1 from numLoci
        unsigned long long int lociPerThread;
        if (numLoci == 0) {
            lociPerThread = (unsigned long long)(size/(numIndividuals*2))/(unsigned long long)numThreads;
        } else {
            lociPerThread = (unsigned long long)numLoci/(unsigned long long)numThreads;
        }

        std::cout << "Initialized lociPerThread with " << numLoci << std::endl;

        std::vector<std::thread> threadsVec;
        for (int threadRunning = 0; threadRunning < numThreads; threadRunning++) {
            std::cout << "Got to the function call. Running thread # " << threadRunning << std::endl;
            unsigned long long int firstLocus = (unsigned long long int) threadRunning * lociPerThread;
            unsigned long long int finishingLocus = ((unsigned long long int) threadRunning * lociPerThread) + lociPerThread - (unsigned long long)1.0;
            std::cout << "Set firstLocus to " << firstLocus << " and finishingLocus to " << finishingLocus << std::endl;

            threadsVec.push_back(std::thread(calcPWPforRange, firstLocus, finishingLocus, numIndividuals, std::ref(readCounts), std::ref(pwpThreads[threadRunning]), std::ref(weightingsThreads[threadRunning])));
        }

        // Wait on threads to finish
        for (int i = 0; i < numThreads; ++i) {
            threadsVec[i].join();
            std::cout << "Joined thread " << i << std::endl;
        }
        std::cout << "All threads completed running" << std::endl;

        // Now aggregate the results of the threads and print final results
        std::vector<std::vector<long double>> weightingsSum(numIndividuals, std::vector<long double>(numIndividuals,0));
        std::vector<std::vector<long double>> pwpSum(numIndividuals, std::vector<long double>(numIndividuals,0));

        for (int tortoise = 0; tortoise < numIndividuals; tortoise++) {
            for (int comparisonTortoise = 0; comparisonTortoise <= tortoise; comparisonTortoise++) {
                for (int threadVector = 0; threadVector < numThreads; threadVector++) {
                    weightingsSum[tortoise][comparisonTortoise] += weightingsThreads[threadVector][tortoise][comparisonTortoise];
                    pwpSum[tortoise][comparisonTortoise] += pwpThreads[threadVector][tortoise][comparisonTortoise];
                }
            }
        }

        std::cout << "Finished summing the threads vectors" << std::endl;

        // Now print out the final output to the pairwise pi file:
        std::ofstream pwpOUT (outFile);
        int rowCounter = 0;
        if (!pwpOUT) {
            std::cerr << "Crap, " << outFile << "didn't open!" << std::endl;
        } else {
            for (int tortoise=0; tortoise < numIndividuals; tortoise++) {
                for (int comparisonTortoise = 0; comparisonTortoise <= tortoise; comparisonTortoise++) {
                    rowCounter++;

                    //std::cout << "Made it past the beginning of the last end for loop" << std::endl;
                    //std::cout << "Tortoise numbers: " << tortoise << " and " << comparisonTortoise << std::endl;
                    if (weightingsSum[tortoise][comparisonTortoise] > 0) {
                        //std::cout << weightings[tortoise][comparisonTortoise] << std::endl;
                        //std::cout << pwp[tortoise][comparisonTortoise] / weightings[tortoise][comparisonTortoise] << std::endl;
                        std::cout << std::fixed;
                        std::cout << "Weightings for tortoise " << tortoise << " and comparisonTortoise " << comparisonTortoise << " : " << weightingsSum[tortoise][comparisonTortoise] << std::endl;
                        std::cout << "PWP for tortoise " << tortoise << " and comparisonTortoise " << comparisonTortoise << " : " << pwpSum[tortoise][comparisonTortoise] << std::endl;
                        std::cout << std::scientific;
                        pwpOUT << pwpSum[tortoise][comparisonTortoise] / weightingsSum[tortoise][comparisonTortoise] << std::endl;
                    } else {
                        pwpOUT << "NA" << std::endl;
                    }
                }
            }
        }
    } else std::cout << "Unable to open file";

    return 0;
}

//int calcPWPforRange (unsigned long long startingLocus, unsigned long long endingLocus, int numIndividuals, const std::vector<BYTE>& mainReadCountVector, std::vector< std::vector<long double> > & threadPWP, std::vector< std::vector<long double> > & threadWeightings) {
int calcPWPforRange (unsigned long long startingLocus, unsigned long long endingLocus, int numIndividuals, std::vector<unsigned char>& mainReadCountVector, std::vector<std::vector<long double>>& threadPWP, std::vector<std::vector<unsigned long long int>>& threadWeightings) {

     std::cout << "Calculating PWP for the following locus range: " << startingLocus << " to " << endingLocus << std::endl;
     for( unsigned long long locus = startingLocus; locus < endingLocus; locus++) {
     //std::cout << "Processing locus # " << locus << std::endl;
         if (locus % 100000 == 0) {
             std::cout << locus << " loci processed through calcPWPfromBinaryFile" << std::endl;
         }

         unsigned long long coverages[numIndividuals];
         long double *majorAlleleFreqs = new long double[numIndividuals]; // This will hold the major allele frequencies for that locus for each tortoise

         for( int tortoise = 0; tortoise < numIndividuals; tortoise++ ) {
             unsigned long long majorIndex = locus * (numIndividuals*2) + 2 * tortoise;
             unsigned long long minorIndex = locus * (numIndividuals*2) + 2 * tortoise + 1;

             coverages[tortoise] = int(mainReadCountVector[majorIndex]) + int(mainReadCountVector[minorIndex]); // Hold the coverages for each locus
             if ( coverages[tortoise] > 0 ) {
                 //std::cout << "Made it to line 222 for locus " << locus << std::endl;
                 majorAlleleFreqs[tortoise] = (long double)mainReadCountVector[majorIndex] / (long double)coverages[tortoise]; // Not necessarily an int, but could be 0 or 1

                 if (coverages[tortoise] > 1) {
                     unsigned long long locusWeighting = (unsigned long long) (coverages[tortoise]*(coverages[tortoise]-1));
                     threadWeightings[tortoise][tortoise] += (unsigned long long)locusWeighting; // This is an int--discrete number of reads

                     //threadPWP[tortoise][tortoise] += (long double)(locusWeighting) * ((long double)2.0 * majorAlleleFreqs[tortoise] * ((long double)(coverages[tortoise]) - (long double)(mainReadCountVector[majorIndex]))) / (long double)((coverages[tortoise])-(long double)1.0);

                     //Cancel out the "coverages[tortoise]-1"
                     //threadPWP[tortoise][tortoise] += (long double)(coverages[tortoise]) * ((long double)2.0 * majorAlleleFreqs[tortoise] * ((long double)(coverages[tortoise]) - (long double)(mainReadCountVector[majorIndex])));
                     threadPWP[tortoise][tortoise] += (long double)(locusWeighting) * ((long double)2.0 * majorAlleleFreqs[tortoise] * ((long double)(coverages[tortoise]) - (long double)(mainReadCountVector[majorIndex])) / (long double)((coverages[tortoise]-1)));

                     //threadPWP[tortoise][tortoise] += locusWeighting*(2*majorAlleleFreqs[tortoise] * (coverages[tortoise]-majorReadCounts)) / (coverages[tortoise]-1)
                 }

                 for( int comparisonTortoise = 0; comparisonTortoise < tortoise; comparisonTortoise++) {
                     if (coverages[comparisonTortoise] > 0) {
                         long double locusWeighting = (long double)coverages[tortoise] * (long double)(coverages[comparisonTortoise]-1.0);

                         threadWeightings[tortoise][comparisonTortoise] += locusWeighting;

                         threadPWP[tortoise][comparisonTortoise] += (long double)locusWeighting * (majorAlleleFreqs[tortoise] * ((long double)1.0-majorAlleleFreqs[comparisonTortoise]) + majorAlleleFreqs[comparisonTortoise] * ((long double)1.0-majorAlleleFreqs[tortoise]));
                    }
                }
            }
        }
        delete[] majorAlleleFreqs; // Needed to avoid memory leaks
    }
    std::cout << "Finished thread ending on locus " << endingLocus << std::endl;
    return 0;
}

<commit_msg>Minor changes<commit_after>//
//  calcPWP.cpp
//
//
//  Created by Evan McCartney-Melstad on 1/10/15.
//
//

#include "calcPWP.h"
#include <iostream>
#include <vector>
#include <fstream>
#include <thread>
#include <string>

int calcPWPfromBinaryFile (std::string binaryFile, unsigned long long int numLoci, const int numIndividuals, std::string outFile, int numThreads) {

    //****MODIFY THIS TO ONLY READ IN N LOCI AT A TIME, INSTEAD OF USING THE ENTIRE FILE****

    std::cout << "Number of threads: " << numThreads << std::endl;
    std::streampos size;
    std::ifstream file (binaryFile, std::ios::in|std::ios::binary|std::ios::ate);
    //ifstream file ("test500k.binary8bitunsigned", ios::in|ios::binary|ios::ate);
    if (file.is_open()) {
        size = file.tellg(); // Just a variable that shows position of stream--at end since ios::ate, so it's the file size. PROBABLY WON'T WORK FOR FILES LARGER THAN ~ 2GB!
        file.seekg (0, std::ios::beg); // Go back to the beginning of the file
        //file.read((char*)readCounts, size); // cast to a char* to give to file.read

        //unsigned char* readCounts;
        //readCounts = new unsigned char[size];
        std::vector<unsigned char> readCounts(size);
        file.read((char*) &readCounts[0], size);
        file.close();

        std::cout << "the entire file content is in memory" << std::endl;
        std::cout << "the total size of the file is " << size << std::endl;
        std::cout << "the number of elements in the readCounts vector is: " << readCounts.size() << std::endl; // Will give the total size bytes divided by the size of one element--so it gives the number of elements

        /* We are going to split the loci between numThreads threads. Each thread will modify two multidimensional
         vectors of the forms std::vector< std::vector<long double> > pwp(numIndividuals, std::vector<long double>(numIndividuals,0))    and   std::vector< std::vector<unsigned long long int> > weightings(numIndividuals, std::vector<unsigned long long int>(numIndividuals,0))

         First, we'll generate all of these vectors, which apparently in C++ needs to be constructed of a
         vector of two-dimensional vectors...
         */
        std::vector<std::vector<std::vector<long double>>> pwpThreads(numThreads, std::vector<std::vector<long double>> (numIndividuals, std::vector<long double> (numIndividuals,0) ) ); //pwpThreads[0] is the first 2D array for the first thread, etc...
        std::vector<std::vector<std::vector<unsigned long long int>>> weightingsThreads(numThreads, std::vector<std::vector<unsigned long long int> > (numIndividuals, std::vector<unsigned long long int> (numIndividuals,0) ) );

        std::cout << "Initialized the 3d vectors" << std::endl;

        // Now we need to determine how many loci for each thread. If we want to use the entire binary file, instead of numLoci loci, then change this to lociPerThread = (size/(numIndividuals*2))/numThreads
        //unsigned long long int lociPerThread = numLoci / numThreads;

        //unsigned long long int lociPerThread = (readCounts.size()-1)/numThreads; // loci starts with 0, so need to subtract 1 from numLoci
        unsigned long long int lociPerThread;
        if (numLoci == 0) {
            lociPerThread = (unsigned long long)(size/(numIndividuals*2))/(unsigned long long)numThreads;
        } else {
            lociPerThread = (unsigned long long)numLoci/(unsigned long long)numThreads;
        }

        std::cout << "Initialized lociPerThread with " << numLoci << std::endl;

        std::vector<std::thread> threadsVec;
        for (int threadRunning = 0; threadRunning < numThreads; threadRunning++) {
            std::cout << "Got to the function call. Running thread # " << threadRunning << std::endl;
            unsigned long long int firstLocus = (unsigned long long int) threadRunning * lociPerThread;
            unsigned long long int finishingLocus = ((unsigned long long int) threadRunning * lociPerThread) + lociPerThread - (unsigned long long)1.0;
            std::cout << "Set firstLocus to " << firstLocus << " and finishingLocus to " << finishingLocus << std::endl;

            threadsVec.push_back(std::thread(calcPWPforRange, firstLocus, finishingLocus, numIndividuals, std::ref(readCounts), std::ref(pwpThreads[threadRunning]), std::ref(weightingsThreads[threadRunning])));
        }

        // Wait on threads to finish
        for (int i = 0; i < numThreads; ++i) {
            threadsVec[i].join();
            std::cout << "Joined thread " << i << std::endl;
        }
        std::cout << "All threads completed running" << std::endl;

        // Now aggregate the results of the threads and print final results
        std::vector<std::vector<long double>> weightingsSum(numIndividuals, std::vector<long double>(numIndividuals,0));
        std::vector<std::vector<long double>> pwpSum(numIndividuals, std::vector<long double>(numIndividuals,0));

        for (int tortoise = 0; tortoise < numIndividuals; tortoise++) {
            for (int comparisonTortoise = 0; comparisonTortoise <= tortoise; comparisonTortoise++) {
                for (int threadVector = 0; threadVector < numThreads; threadVector++) {
                    weightingsSum[tortoise][comparisonTortoise] += weightingsThreads[threadVector][tortoise][comparisonTortoise];
                    pwpSum[tortoise][comparisonTortoise] += pwpThreads[threadVector][tortoise][comparisonTortoise];
                }
            }
        }

        std::cout << "Finished summing the threads vectors" << std::endl;

        // Now print out the final output to the pairwise pi file:
        std::ofstream pwpOUT (outFile);
        int rowCounter = 0;
        if (!pwpOUT) {
            std::cerr << "Crap, " << outFile << "didn't open!" << std::endl;
        } else {
            for (int tortoise=0; tortoise < numIndividuals; tortoise++) {
                for (int comparisonTortoise = 0; comparisonTortoise <= tortoise; comparisonTortoise++) {
                    rowCounter++;

                    //std::cout << "Made it past the beginning of the last end for loop" << std::endl;
                    //std::cout << "Tortoise numbers: " << tortoise << " and " << comparisonTortoise << std::endl;
                    if (weightingsSum[tortoise][comparisonTortoise] > 0) {
                        //std::cout << weightings[tortoise][comparisonTortoise] << std::endl;
                        //std::cout << pwp[tortoise][comparisonTortoise] / weightings[tortoise][comparisonTortoise] << std::endl;
                        std::cout << std::fixed;
                        std::cout << "Weightings for tortoise " << tortoise << " and comparisonTortoise " << comparisonTortoise << " : " << weightingsSum[tortoise][comparisonTortoise] << std::endl;
                        std::cout << "PWP for tortoise " << tortoise << " and comparisonTortoise " << comparisonTortoise << " : " << pwpSum[tortoise][comparisonTortoise] << std::endl;
                        std::cout << std::scientific;
                        pwpOUT << pwpSum[tortoise][comparisonTortoise] / weightingsSum[tortoise][comparisonTortoise] << std::endl;
                    } else {
                        pwpOUT << "NA" << std::endl;
                    }
                }
            }
        }
    } else std::cout << "Unable to open file";

    return 0;
}

//int calcPWPforRange (unsigned long long startingLocus, unsigned long long endingLocus, int numIndividuals, const std::vector<BYTE>& mainReadCountVector, std::vector< std::vector<long double> > & threadPWP, std::vector< std::vector<long double> > & threadWeightings) {
int calcPWPforRange (unsigned long long startingLocus, unsigned long long endingLocus, int numIndividuals, std::vector<unsigned char>& mainReadCountVector, std::vector<std::vector<long double>>& threadPWP, std::vector<std::vector<unsigned long long int>>& threadWeightings) {

     std::cout << "Calculating PWP for the following locus range: " << startingLocus << " to " << endingLocus << std::endl;
     for( unsigned long long locus = startingLocus; locus < endingLocus; locus++) {
     //std::cout << "Processing locus # " << locus << std::endl;
         if (locus % 100000 == 0) {
             std::cout << locus << " loci processed through calcPWPfromBinaryFile" << std::endl;
         }

         unsigned long long coverages[numIndividuals];
         long double *majorAlleleFreqs = new long double[numIndividuals]; // This will hold the major allele frequencies for that locus for each tortoise

         for( int tortoise = 0; tortoise < numIndividuals; tortoise++ ) {
             unsigned long long majorIndex = locus * (numIndividuals*2) + 2 * tortoise;
             unsigned long long minorIndex = locus * (numIndividuals*2) + 2 * tortoise + 1;

             coverages[tortoise] = int(mainReadCountVector[majorIndex]) + int(mainReadCountVector[minorIndex]); // Hold the coverages for each locus
             if ( coverages[tortoise] > 0 ) {
                 //std::cout << "Made it to line 222 for locus " << locus << std::endl;
                 majorAlleleFreqs[tortoise] = (long double)mainReadCountVector[majorIndex] / (long double)coverages[tortoise]; // Not necessarily an int, but could be 0 or 1

                 if (coverages[tortoise] > 1) {
                     unsigned long long locusWeighting = (unsigned long long) (coverages[tortoise]*(coverages[tortoise]-1));
                     threadWeightings[tortoise][tortoise] += (unsigned long long)locusWeighting; // This is an int--discrete number of reads

                     //threadPWP[tortoise][tortoise] += (long double)(locusWeighting) * ((long double)2.0 * majorAlleleFreqs[tortoise] * ((long double)(coverages[tortoise]) - (long double)(mainReadCountVector[majorIndex]))) / (long double)((coverages[tortoise])-(long double)1.0);

                     //Cancel out the "coverages[tortoise]-1"
                     //threadPWP[tortoise][tortoise] += (long double)(coverages[tortoise]) * ((long double)2.0 * majorAlleleFreqs[tortoise] * ((long double)(coverages[tortoise]) - (long double)(mainReadCountVector[majorIndex])));
                     threadPWP[tortoise][tortoise] += (long double)(locusWeighting) * ((long double)2.0 * majorAlleleFreqs[tortoise] * ((long double)(coverages[tortoise]) - (long double)(mainReadCountVector[majorIndex])) / (long double)((coverages[tortoise]-1)));

                     //threadPWP[tortoise][tortoise] += locusWeighting*(2*majorAlleleFreqs[tortoise] * (coverages[tortoise]-majorReadCounts)) / (coverages[tortoise]-1)
                 }

                 for( int comparisonTortoise = 0; comparisonTortoise < tortoise; comparisonTortoise++) {
                     if (coverages[comparisonTortoise] > 0) {
                         long double locusWeighting = (long double)coverages[tortoise] * (long double)(coverages[comparisonTortoise]);

                         threadWeightings[tortoise][comparisonTortoise] += locusWeighting;

                         threadPWP[tortoise][comparisonTortoise] += (long double)locusWeighting * (majorAlleleFreqs[tortoise] * ((long double)1.0-majorAlleleFreqs[comparisonTortoise]) + majorAlleleFreqs[comparisonTortoise] * ((long double)1.0-majorAlleleFreqs[tortoise]));
                    }
                }
            }
        }
        delete[] majorAlleleFreqs; // Needed to avoid memory leaks
    }
    std::cout << "Finished thread ending on locus " << endingLocus << std::endl;
    return 0;
}

<|endoftext|>


<commit_before>#ifndef _GUARD_CAST_HPP_
#define _GUARD_CAST_HPP_

#include <limits>

#include "bpmodule/pragma.h"
#include "bpmodule/exception/MathException.hpp"
#include "bpmodule/mangle/Mangle.hpp"

namespace bpmodule {
namespace math {

/*! Perform a safe cast between integer types or between floating point types
 *
 * Checks for overflows and underflows.
 *
 * Cannot be used to convert integer <-> floating point. Use round_cast instead.
 *
 * \throw bpmodule::exception::MathException if there is a problem (overflow, underflow, etc)
 */
template<typename Target, typename Source>
Target numeric_cast(Source s)
{
    static_assert(  ( std::is_integral<Source>::value && std::is_integral<Target>::value) ||
                    ( std::is_floating_point<Source>::value && std::is_floating_point<Target>::value),
                    "Attempting to perform integer <-> floating point conversion using numeric_cast. Consider round_cast");

    // check for overflow, underflow
    if(s > std::numeric_limits<Source>::max())
        throw exception::MathException("Error in numeric_cast",
                                       "desc", "source value overflows target type",
                                       "fpfrom", mangle::DemangleCppType<Source>(),
                                       "fpto", mangle::DemangleCppType<Target>());

    if(s < std::numeric_limits<Source>::lowest())
        throw exception::MathException("Error in numeric_cast",
                                       "desc", "source value underflows target type",
                                       "fpfrom", mangle::DemangleCppType<Source>(),
                                       "fpto", mangle::DemangleCppType<Target>());

    // if both are integral types, checking for overflow/underflow
    // is all that's needed
    if(std::is_integral<Source>::value && std::is_integral<Target>::value)
        return static_cast<Target>(s);

    // if both are floating point
    // we have to check that the conversion is valid
    // Hackish way, but convert to target and back, then compare
    if(std::is_floating_point<Source>::value && std::is_floating_point<Target>::value)
    {
        // check for overflow and underflow
        Target t = static_cast<Target>(s);
        Source s2 = static_cast<Source>(t);

        // ignore this warning -- we are doing it on purpose
        PRAGMA_WARNING_PUSH
        PRAGMA_WARNING_IGNORE_FP_EQUALITY
        if(s == s2)
            return t;
        else
            throw exception::MathException("Error in numeric_cast",
                                           "desc", "Floating point conversion results in loss of precision",
                                           "fpfrom", mangle::DemangleCppType<Source>(),
                                           "fpto", mangle::DemangleCppType<Target>());
        PRAGMA_WARNING_POP
    }

    throw std::logic_error("numeric_cast unhandled types");
}

/*! \brief Convert between integer and floating point types, with rounding
 *
 * \todo NYI
 */
template<typename Target, typename Source>
Target round_cast(Source s)
{
    static_assert(std::is_same<Source, Target>::value, "TODO: round_cast between different types");
    return s;
}

} // close namespace math
} // close namespace bpmodule

#endif
<commit_msg>Expand checking in math::numeric_cast<commit_after>#ifndef _GUARD_CAST_HPP_
#define _GUARD_CAST_HPP_

#include <limits>

#include "bpmodule/pragma.h"
#include "bpmodule/exception/MathException.hpp"
#include "bpmodule/mangle/Mangle.hpp"

namespace bpmodule {
namespace math {

/*! Perform a safe cast between integer types or between floating point types
 *
 * Checks for overflows and underflows, as well as loss of precision with floating
 * point conversions.
 *
 * Cannot be used to convert integer <-> floating point. Use round_cast instead.
 *
 * \throw bpmodule::exception::MathException if there is a problem (overflow, underflow, etc)
 */
template<typename Target, typename Source>
Target numeric_cast(Source s)
{
    static_assert(  ( std::is_integral<Source>::value && std::is_integral<Target>::value) ||
                    ( std::is_floating_point<Source>::value && std::is_floating_point<Target>::value),
                    "Attempting to perform integer <-> floating point conversion using numeric_cast. Consider round_cast");

    // no casting
    if(std::is_same<Target, Source>::value)
        return static_cast<Target>(s);  // cast to make compiler warnings go away

    ////////////////////////////////////////////////////////////////////////////////
    // this is written with branching so that the limits checking isn't always done
    // (ie, going from short->int should be pretty much optimized out)
    //
    // Actually, most branching shown here should be optimized out at compile
    ////////////////////////////////////////////////////////////////////////////////

    ///////////////////
    // for integers
    ///////////////////
    if(std::is_integral<Source>::value && std::is_integral<Target>::value)
    {
        // both are signed or unsigned
        if(std::is_signed<Source>::value == std::is_signed<Target>::value)
        {
            // going from smaller to larger type - ok
            if(std::numeric_limits<Target>::digits >= std::numeric_limits<Source>::digits)
                return static_cast<Target>(s);
            else
            {
                // source is larger type than target. check limits
                Source tmax = static_cast<Source>(std::numeric_limits<Target>::max());
                Source tmin = static_cast<Source>(std::numeric_limits<Target>::lowest());
                if(s > tmax)
                    throw exception::MathException("Error in numeric_cast",
                                                   "desc", "source value overflows target type",
                                                   "fpfrom", mangle::DemangleCppType<Source>(),
                                                   "fpto", mangle::DemangleCppType<Target>());
                else if(s < tmin)
                    throw exception::MathException("Error in numeric_cast",
                                                   "desc", "source value underflows target type",
                                                   "fpfrom", mangle::DemangleCppType<Source>(),
                                                   "fpto", mangle::DemangleCppType<Target>());

                else // safe!
                    return static_cast<Target>(s);

            }
        }
        else if(std::is_signed<Source>::value) // Source is signed, Target is unsigned
        {
            if(s < 0)
                throw exception::MathException("Error in numeric_cast",
                                               "desc", "source value underflows target type",
                                               "fpfrom", mangle::DemangleCppType<Source>(),
                                               "fpto", mangle::DemangleCppType<Target>());

            // going from smaller to larger type - ok (since s >= 0)
            if(std::numeric_limits<Target>::digits >= std::numeric_limits<Source>::digits)
                return static_cast<Target>(s);
            else
            {
                // source is larger type than target. check other limit
                // casting to Source type should be ok since sizeof(Source) > sizeof(Target)
                Source tmax = static_cast<Source>(std::numeric_limits<Target>::max());
                if(s > tmax)
                    throw exception::MathException("Error in numeric_cast",
                                                   "desc", "source value overflows target type",
                                                   "fpfrom", mangle::DemangleCppType<Source>(),
                                                   "fpto", mangle::DemangleCppType<Target>());

                else // safe!
                    return static_cast<Target>(s);

            }
        }
        else  // Source is unsigned, target is signed
        {
            // going from smaller to larger type - ok
            // (since numeric_limits::digits reports bits without sign bit)
            if(std::numeric_limits<Target>::digits >= std::numeric_limits<Source>::digits)
                return static_cast<Target>(s);
            else
            {
                // source is larger type than target. check max limit
                // casting to Source type should be ok since sizeof(Source) > sizeof(Target)
                Source tmax = static_cast<Source>(std::numeric_limits<Target>::max());
                if(s > tmax)
                    throw exception::MathException("Error in numeric_cast",
                                                   "desc", "source value overflows target type",
                                                   "fpfrom", mangle::DemangleCppType<Source>(),
                                                   "fpto", mangle::DemangleCppType<Target>());

                else // safe!
                    return static_cast<Target>(s);

            }
        }
    }

    // if both are floating point
    // we have to check that the conversion is valid
    else if(std::is_floating_point<Source>::value && std::is_floating_point<Target>::value)
    {
        // Hackish way, but convert to target and back, then compare
        // check for overflow and underflow
        Target t = static_cast<Target>(s);
        Source s2 = static_cast<Source>(t);

        // ignore this warning -- we are doing it on purpose
        PRAGMA_WARNING_PUSH
        PRAGMA_WARNING_IGNORE_FP_EQUALITY
        if(s == s2)
            return t;
        else
            throw exception::MathException("Error in numeric_cast",
                                           "desc", "Floating point conversion results in loss of precision",
                                           "fpfrom", mangle::DemangleCppType<Source>(),
                                           "fpto", mangle::DemangleCppType<Target>());
        PRAGMA_WARNING_POP
    }

    else
        throw std::logic_error("numeric_cast unhandled types");
}

/*! \brief Convert between integer and floating point types, with rounding
 *
 * \todo NYI
 */
template<typename Target, typename Source>
Target round_cast(Source s)
{
    static_assert(std::is_same<Source, Target>::value, "TODO: round_cast between different types");
    return s;
}

} // close namespace math
} // close namespace bpmodule

#endif
<|endoftext|>