<commit_before>#include "Tracing.h"
#include "IRMutator.h"
#include "IROperator.h"
#include "runtime/HalideRuntime.h"

namespace Halide {
namespace Internal {

int tracing_level() {
    char *trace = getenv("HL_TRACE");
    return trace ? atoi(trace) : 0;
}

using std::vector;
using std::map;
using std::string;

class InjectTracing : public IRMutator {
public:
    const map<string, Function> &env;
    Function output;
    int global_level;
    InjectTracing(const map<string, Function> &e,
                  Function o) : env(e),
                                output(o),
                                global_level(tracing_level()) {}

private:
    using IRMutator::visit;

    void visit(const Call *op) {

        // Calls inside of an address_of don't count, but we want to
        // visit the args of the inner call.
        if (op->call_type == Call::Intrinsic && op->name == Call::address_of) {
            internal_assert(op->args.size() == 1);
            const Call *c = op->args[0].as<Call>();

            bool unchanged = true;
            vector<Expr> new_args(c->args.size());
            for (size_t i = 0; i < c->args.size(); i++) {
                new_args[i] = mutate(c->args[i]);
                unchanged = unchanged && (new_args[i].same_as(c->args[i]));
            }

            if (unchanged) {
                expr = op;
                return;
            } else {
                Expr inner = Call::make(c->type, c->name, new_args, c->call_type,
                                        c->func, c->value_index, c->image, c->param);
                expr = Call::make(Handle(), Call::address_of, vec(inner), Call::Intrinsic);
                return;
            }

        }

        IRMutator::visit(op);
        op = expr.as<Call>();
        internal_assert(op);

        if (op->call_type != Call::Halide) {
            return;
        }

        Function f = op->func;
        bool inlined = !f.same_as(output) && f.schedule().compute_level().is_inline();

        if (f.is_tracing_loads() || (global_level > 2 && !inlined)) {

            // Wrap the load in a call to trace_load
            vector<Expr> args;
            args.push_back(f.name());
            args.push_back(halide_trace_load);
            args.push_back(Variable::make(Int(32), op->name + ".trace_id"));
            args.push_back(op->value_index);
            args.push_back(op);
            args.insert(args.end(), op->args.begin(), op->args.end());

            expr = Call::make(op->type, Call::trace_expr, args, Call::Intrinsic);
        }

    }

    void visit(const Provide *op) {
        IRMutator::visit(op);
        op = stmt.as<Provide>();
        internal_assert(op);

        map<string, Function>::const_iterator iter = env.find(op->name);
        if (iter == env.end()) return;
        Function f = iter->second;
        bool inlined = !f.same_as(output) && f.schedule().compute_level().is_inline();

        if (f.is_tracing_stores() || (global_level > 1 && !inlined)) {
            // Wrap each expr in a tracing call

            const vector<Expr> &values = op->values;
            vector<Expr> traces(op->values.size());

            for (size_t i = 0; i < values.size(); i++) {
                vector<Expr> args;
                args.push_back(f.name());
                args.push_back(halide_trace_store);
                args.push_back(Variable::make(Int(32), op->name + ".trace_id"));
                args.push_back((int)i);
                args.push_back(values[i]);
                args.insert(args.end(), op->args.begin(), op->args.end());
                traces[i] = Call::make(values[i].type(), Call::trace_expr, args, Call::Intrinsic);
            }

            stmt = Provide::make(op->name, traces, op->args);
        }
    }

    void visit(const Realize *op) {
        IRMutator::visit(op);
        op = stmt.as<Realize>();
        internal_assert(op);

        map<string, Function>::const_iterator iter = env.find(op->name);
        if (iter == env.end()) return;
        Function f = iter->second;
        if (f.is_tracing_realizations() || global_level > 0) {

            // Throw a tracing call before and after the realize body
            vector<Expr> args;
            args.push_back(op->name);
            args.push_back(halide_trace_begin_realization); // event type for begin realization
            args.push_back(0); // realization id
            //TODO: args.push_back(op->condition);

            args.push_back(0); // value index
            args.push_back(0); // value

            for (size_t i = 0; i < op->bounds.size(); i++) {
                args.push_back(op->bounds[i].min);
                args.push_back(op->bounds[i].extent);
            }

            // Begin realization returns a unique token to pass to further trace calls affecting this buffer.

            Expr call_before = Call::make(Int(32), Call::trace, args, Call::Intrinsic);
            args[1] = halide_trace_end_realization;
            args[2] = Variable::make(Int(32), op->name + ".trace_id");
            Expr call_after = Call::make(Int(32), Call::trace, args, Call::Intrinsic);
            Stmt new_body = op->body;
            new_body = Block::make(new_body, Evaluate::make(call_after));
            new_body = LetStmt::make(op->name + ".trace_id", call_before, new_body);
            stmt = Realize::make(op->name, op->types, op->bounds, op->condition, new_body);
        } else if (f.is_tracing_stores() || f.is_tracing_loads()) {
            // We need a trace id defined to pass to the loads and stores
            Stmt new_body = op->body;
            new_body = LetStmt::make(op->name + ".trace_id", 0, new_body);
            stmt = Realize::make(op->name, op->types, op->bounds, op->condition, new_body);
        }

    }

    void visit(const Pipeline *op) {
        IRMutator::visit(op);
        op = stmt.as<Pipeline>();
        internal_assert(op);
        map<string, Function>::const_iterator iter = env.find(op->name);
        if (iter == env.end()) return;
        Function f = iter->second;
        if (f.is_tracing_realizations() || global_level > 0) {
            // Throw a tracing call around each pipeline event
            vector<Expr> args;
            args.push_back(op->name);
            args.push_back(0);
            args.push_back(Variable::make(Int(32), op->name + ".trace_id"));
            args.push_back(0); // value index
            args.push_back(0); // value

            // Use the size of the pure step

            for (int i = 0; i < f.dimensions(); i++) {
                Expr min = Variable::make(Int(32), f.name() + ".s0." + f.args()[i] + ".min");
                Expr max = Variable::make(Int(32), f.name() + ".s0." + f.args()[i] + ".max");
                Expr extent = (max + 1) - min;
                args.push_back(min);
                args.push_back(extent);
            }

            Expr call;
            Stmt new_update;
            if (op->update.defined()) {
                args[1] = halide_trace_update;
                call = Call::make(Int(32), Call::trace, args, Call::Intrinsic);
                new_update = Block::make(Evaluate::make(call), op->update);
            }

            args[1] = halide_trace_consume;
            call = Call::make(Int(32), Call::trace, args, Call::Intrinsic);
            Stmt new_consume = Block::make(Evaluate::make(call), op->consume);

            args[1] = halide_trace_end_consume;
            call = Call::make(Int(32), Call::trace, args, Call::Intrinsic);
            new_consume = Block::make(new_consume, Evaluate::make(call));

            stmt = Pipeline::make(op->name, op->produce, new_update, new_consume);

            args[1] = halide_trace_produce;
            call = Call::make(Int(32), Call::trace, args, Call::Intrinsic);
            stmt = LetStmt::make(f.name() + ".trace_id", call, stmt);
        }

    }
};

Stmt inject_tracing(Stmt s, const map<string, Function> &env, Function output) {
    Stmt original = s;
    InjectTracing tracing(env, output);

    // Add a dummy realize block for the output buffers
    Region output_region;
    Parameter output_buf = output.output_buffers()[0];
    internal_assert(output_buf.is_buffer());
    for (int i = 0; i < output.dimensions(); i++) {
        string d = int_to_string(i);
        Expr min = Variable::make(Int(32), output_buf.name() + ".min." + d);
        Expr extent = Variable::make(Int(32), output_buf.name() + ".extent." + d);
        output_region.push_back(Range(min, extent));
    }
    s = Realize::make(output.name(), output.output_types(), output_region, const_true(), s);

    // Inject tracing calls
    s = tracing.mutate(s);

    // Strip off the dummy realize block
    const Realize *r = s.as<Realize>();
    internal_assert(r);
    s = r->body;

    // Unless tracing was a no-op, add a call to shut down the trace
    // (which flushes the output stream)
    if (!s.same_as(original)) {
        Expr flush = Call::make(Int(32), "halide_shutdown_trace", vector<Expr>(), Call::Extern);
        s = Block::make(s, AssertStmt::make(flush == 0, "Failed to flush trace", vector<Expr>()));
    }
    return s;
}

}
}
<commit_msg>Not necessary to trace condition of Realize.<commit_after>#include "Tracing.h"
#include "IRMutator.h"
#include "IROperator.h"
#include "runtime/HalideRuntime.h"

namespace Halide {
namespace Internal {

int tracing_level() {
    char *trace = getenv("HL_TRACE");
    return trace ? atoi(trace) : 0;
}

using std::vector;
using std::map;
using std::string;

class InjectTracing : public IRMutator {
public:
    const map<string, Function> &env;
    Function output;
    int global_level;
    InjectTracing(const map<string, Function> &e,
                  Function o) : env(e),
                                output(o),
                                global_level(tracing_level()) {}

private:
    using IRMutator::visit;

    void visit(const Call *op) {

        // Calls inside of an address_of don't count, but we want to
        // visit the args of the inner call.
        if (op->call_type == Call::Intrinsic && op->name == Call::address_of) {
            internal_assert(op->args.size() == 1);
            const Call *c = op->args[0].as<Call>();

            bool unchanged = true;
            vector<Expr> new_args(c->args.size());
            for (size_t i = 0; i < c->args.size(); i++) {
                new_args[i] = mutate(c->args[i]);
                unchanged = unchanged && (new_args[i].same_as(c->args[i]));
            }

            if (unchanged) {
                expr = op;
                return;
            } else {
                Expr inner = Call::make(c->type, c->name, new_args, c->call_type,
                                        c->func, c->value_index, c->image, c->param);
                expr = Call::make(Handle(), Call::address_of, vec(inner), Call::Intrinsic);
                return;
            }

        }

        IRMutator::visit(op);
        op = expr.as<Call>();
        internal_assert(op);

        if (op->call_type != Call::Halide) {
            return;
        }

        Function f = op->func;
        bool inlined = !f.same_as(output) && f.schedule().compute_level().is_inline();

        if (f.is_tracing_loads() || (global_level > 2 && !inlined)) {

            // Wrap the load in a call to trace_load
            vector<Expr> args;
            args.push_back(f.name());
            args.push_back(halide_trace_load);
            args.push_back(Variable::make(Int(32), op->name + ".trace_id"));
            args.push_back(op->value_index);
            args.push_back(op);
            args.insert(args.end(), op->args.begin(), op->args.end());

            expr = Call::make(op->type, Call::trace_expr, args, Call::Intrinsic);
        }

    }

    void visit(const Provide *op) {
        IRMutator::visit(op);
        op = stmt.as<Provide>();
        internal_assert(op);

        map<string, Function>::const_iterator iter = env.find(op->name);
        if (iter == env.end()) return;
        Function f = iter->second;
        bool inlined = !f.same_as(output) && f.schedule().compute_level().is_inline();

        if (f.is_tracing_stores() || (global_level > 1 && !inlined)) {
            // Wrap each expr in a tracing call

            const vector<Expr> &values = op->values;
            vector<Expr> traces(op->values.size());

            for (size_t i = 0; i < values.size(); i++) {
                vector<Expr> args;
                args.push_back(f.name());
                args.push_back(halide_trace_store);
                args.push_back(Variable::make(Int(32), op->name + ".trace_id"));
                args.push_back((int)i);
                args.push_back(values[i]);
                args.insert(args.end(), op->args.begin(), op->args.end());
                traces[i] = Call::make(values[i].type(), Call::trace_expr, args, Call::Intrinsic);
            }

            stmt = Provide::make(op->name, traces, op->args);
        }
    }

    void visit(const Realize *op) {
        IRMutator::visit(op);
        op = stmt.as<Realize>();
        internal_assert(op);

        map<string, Function>::const_iterator iter = env.find(op->name);
        if (iter == env.end()) return;
        Function f = iter->second;
        if (f.is_tracing_realizations() || global_level > 0) {

            // Throw a tracing call before and after the realize body
            vector<Expr> args;
            args.push_back(op->name);
            args.push_back(halide_trace_begin_realization); // event type for begin realization
            args.push_back(0); // realization id
            args.push_back(0); // value index
            args.push_back(0); // value

            for (size_t i = 0; i < op->bounds.size(); i++) {
                args.push_back(op->bounds[i].min);
                args.push_back(op->bounds[i].extent);
            }

            // Begin realization returns a unique token to pass to further trace calls affecting this buffer.

            Expr call_before = Call::make(Int(32), Call::trace, args, Call::Intrinsic);
            args[1] = halide_trace_end_realization;
            args[2] = Variable::make(Int(32), op->name + ".trace_id");
            Expr call_after = Call::make(Int(32), Call::trace, args, Call::Intrinsic);
            Stmt new_body = op->body;
            new_body = Block::make(new_body, Evaluate::make(call_after));
            new_body = LetStmt::make(op->name + ".trace_id", call_before, new_body);
            stmt = Realize::make(op->name, op->types, op->bounds, op->condition, new_body);
        } else if (f.is_tracing_stores() || f.is_tracing_loads()) {
            // We need a trace id defined to pass to the loads and stores
            Stmt new_body = op->body;
            new_body = LetStmt::make(op->name + ".trace_id", 0, new_body);
            stmt = Realize::make(op->name, op->types, op->bounds, op->condition, new_body);
        }

    }

    void visit(const Pipeline *op) {
        IRMutator::visit(op);
        op = stmt.as<Pipeline>();
        internal_assert(op);
        map<string, Function>::const_iterator iter = env.find(op->name);
        if (iter == env.end()) return;
        Function f = iter->second;
        if (f.is_tracing_realizations() || global_level > 0) {
            // Throw a tracing call around each pipeline event
            vector<Expr> args;
            args.push_back(op->name);
            args.push_back(0);
            args.push_back(Variable::make(Int(32), op->name + ".trace_id"));
            args.push_back(0); // value index
            args.push_back(0); // value

            // Use the size of the pure step

            for (int i = 0; i < f.dimensions(); i++) {
                Expr min = Variable::make(Int(32), f.name() + ".s0." + f.args()[i] + ".min");
                Expr max = Variable::make(Int(32), f.name() + ".s0." + f.args()[i] + ".max");
                Expr extent = (max + 1) - min;
                args.push_back(min);
                args.push_back(extent);
            }

            Expr call;
            Stmt new_update;
            if (op->update.defined()) {
                args[1] = halide_trace_update;
                call = Call::make(Int(32), Call::trace, args, Call::Intrinsic);
                new_update = Block::make(Evaluate::make(call), op->update);
            }

            args[1] = halide_trace_consume;
            call = Call::make(Int(32), Call::trace, args, Call::Intrinsic);
            Stmt new_consume = Block::make(Evaluate::make(call), op->consume);

            args[1] = halide_trace_end_consume;
            call = Call::make(Int(32), Call::trace, args, Call::Intrinsic);
            new_consume = Block::make(new_consume, Evaluate::make(call));

            stmt = Pipeline::make(op->name, op->produce, new_update, new_consume);

            args[1] = halide_trace_produce;
            call = Call::make(Int(32), Call::trace, args, Call::Intrinsic);
            stmt = LetStmt::make(f.name() + ".trace_id", call, stmt);
        }

    }
};

Stmt inject_tracing(Stmt s, const map<string, Function> &env, Function output) {
    Stmt original = s;
    InjectTracing tracing(env, output);

    // Add a dummy realize block for the output buffers
    Region output_region;
    Parameter output_buf = output.output_buffers()[0];
    internal_assert(output_buf.is_buffer());
    for (int i = 0; i < output.dimensions(); i++) {
        string d = int_to_string(i);
        Expr min = Variable::make(Int(32), output_buf.name() + ".min." + d);
        Expr extent = Variable::make(Int(32), output_buf.name() + ".extent." + d);
        output_region.push_back(Range(min, extent));
    }
    s = Realize::make(output.name(), output.output_types(), output_region, const_true(), s);

    // Inject tracing calls
    s = tracing.mutate(s);

    // Strip off the dummy realize block
    const Realize *r = s.as<Realize>();
    internal_assert(r);
    s = r->body;

    // Unless tracing was a no-op, add a call to shut down the trace
    // (which flushes the output stream)
    if (!s.same_as(original)) {
        Expr flush = Call::make(Int(32), "halide_shutdown_trace", vector<Expr>(), Call::Extern);
        s = Block::make(s, AssertStmt::make(flush == 0, "Failed to flush trace", vector<Expr>()));
    }
    return s;
}

}
}
<|endoftext|>


<commit_before>#include "Dielectric.h"
#include "Ray.h"
#include "Hitable.h"
#include "Utilities.h"

namespace sol {

Dielectric::Dielectric(float ri)
: refractionIndex(ri) {
}

bool Dielectric::scatter(const Ray &inRay, const HitRecord &hitRecord, Eigen::Vector3f &attenuation, Ray &scattered) {
    Eigen::Vector3f outwardNormal;
    Eigen::Vector3f reflected = reflect(inRay.getDirection(), hitRecord.normal);
    float niOverNt = 0.0;
    attenuation = Eigen::Vector3f(1.0, 1.0, 1.0);
    Eigen::Vector3f refracted;
    if (inRay.getDirection().dot(hitRecord.normal) > 0) {
        outwardNormal = -hitRecord.normal;
        niOverNt = refractionIndex;
    } else {
        outwardNormal = hitRecord.normal;
        niOverNt = 1.0 / refractionIndex;
    }
    if (refract(inRay.getDirection(), outwardNormal, niOverNt, refracted)) {
        scattered = Ray(hitRecord.point, refracted);
    } else {
        scattered = Ray(hitRecord.point, reflected);
        return false;
    }
    return true;
}

}
<commit_msg>add schlick function to Dielectric material<commit_after>#include "Dielectric.h"
#include "Ray.h"
#include "Hitable.h"
#include "Utilities.h"

namespace sol {

Dielectric::Dielectric(float ri)
: refractionIndex(ri) {
}

bool Dielectric::scatter(const Ray &inRay, const HitRecord &hitRecord, Eigen::Vector3f &attenuation, Ray &scattered) {
    Eigen::Vector3f outwardNormal;
    Eigen::Vector3f reflected = reflect(inRay.getDirection(), hitRecord.normal);
    float niOverNt = 0.0;
    attenuation = Eigen::Vector3f(1.0, 1.0, 1.0);
    Eigen::Vector3f refracted;
    float reflectProb = 0.0;
    float cosine = 0.0;

    if (inRay.getDirection().dot(hitRecord.normal) > 0) {
        outwardNormal = -hitRecord.normal;
        niOverNt = refractionIndex;
        cosine = refractionIndex * inRay.getDirection().dot(hitRecord.normal) / inRay.getDirection().norm();
    } else {
        outwardNormal = hitRecord.normal;
        niOverNt = 1.0 / refractionIndex;
        cosine = -inRay.getDirection().dot(hitRecord.normal) / inRay.getDirection().norm();
    }

    if (refract(inRay.getDirection(), outwardNormal, niOverNt, refracted)) {
        reflectProb = schlick(cosine, refractionIndex);
    } else {
        scattered = Ray(hitRecord.point, reflected);
        reflectProb = 1.0;
    }

    if (drand48() < reflectProb) {
        scattered = Ray(hitRecord.point, reflected);
    } else {
        scattered = Ray(hitRecord.point, refracted);
    }

    return true;
}

}
<|endoftext|>


<commit_before>/** \file
 *
 *  Copyright (c) 2015 by Travis Gockel. All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify it under the terms of the Apache License
 *  as published by the Apache Software Foundation, either version 2 of the License, or (at your option) any later
 *  version.
 *
 *  \author Travis Gockel (travis@gockelhut.com)
**/
#include <jsonv/util.hpp>
#include <jsonv/algorithm.hpp>
#include <jsonv/string_view.hpp>
#include <jsonv/coerce.hpp>

#include <sstream>
#include <stdexcept>

namespace jsonv
{

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Merging                                                                                //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

merge_rules::~merge_rules() noexcept = default;

dynamic_merge_rules::dynamic_merge_rules(same_key_function same_key, type_conflict_function type_conflict) :
        same_key(std::move(same_key)),
        type_conflict(std::move(type_conflict))
{ }

dynamic_merge_rules::~dynamic_merge_rules() noexcept = default;

value dynamic_merge_rules::resolve_same_key(path&& current_path, value&& a, value&& b) const
{
    return same_key(std::move(current_path), std::move(a), std::move(b));
}

value dynamic_merge_rules::resolve_type_conflict(path&& current_path, value&& a, value&& b) const
{
    return same_key(std::move(current_path), std::move(a), std::move(b));
}

value throwing_merge_rules::resolve_type_conflict(path&& current_path, value&& a, value&& b) const
{
    throw kind_error(std::string("Found different types at path `") + to_string(current_path) + "': "
                     + to_string(a.kind()) + " and " + to_string(b.kind()));
}

value throwing_merge_rules::resolve_same_key(path&& current_path, value&&, value&&) const
{
    throw std::logic_error(std::string("Cannot merge duplicate key at \"") + to_string(current_path) + "\"");
}

value recursive_merge_rules::resolve_same_key(path&& current_path, value&& a, value&& b) const
{
    return merge_explicit(*this, std::move(current_path), std::move(a), std::move(b));
}

value recursive_merge_rules::resolve_type_conflict(path&&, value&& a, value&& b) const
{
    return coerce_merge(std::move(a), std::move(b));
}

value merge_explicit(const merge_rules& rules,
                     path               current_path,
                     value              a,
                     value              b
                    )
{
    if (  a.kind() != b.kind()
       && !(   (a.kind() == kind::integer && b.kind() == kind::decimal)
            || (a.kind() == kind::decimal && b.kind() == kind::integer)
           )
       )
        return rules.resolve_type_conflict(std::move(current_path), std::move(a), std::move(b));

    switch (a.kind())
    {
        case kind::object:
        {
            value out = object();
            for (value::object_iterator iter = a.begin_object(); iter != a.end_object(); ++iter)
            {
                auto iter_b = b.find(iter->first);
                if (iter_b == b.end_object())
                {
                    out.insert({ iter->first, std::move(iter->second) });
                }
                else
                {
                    out.insert({ iter->first,
                                 rules.resolve_same_key(current_path + iter->first,
                                                        std::move(iter->second),
                                                        std::move(iter_b->second)
                                                       )
                               }
                              );
                    b.erase(iter_b);
                }
            }

            for (value::object_iterator iter = b.begin_object(); iter != b.end_object(); ++iter)
            {
                out.insert({ iter->first, std::move(iter->second) });
            }

            return out;
        }
        case kind::array:
            a.insert(a.end_array(), std::make_move_iterator(b.begin_array()), std::make_move_iterator(b.end_array()));
            return a;
        case kind::boolean:
            return a.as_boolean() || b.as_boolean();
        case kind::integer:
            if (b.kind() == kind::integer)
                return a.as_integer() + b.as_integer();
            // fall through to decimal handler if b is a decimal
        case kind::decimal:
            return a.as_decimal() + b.as_decimal();
        case kind::null:
            return a;
        case kind::string:
            return a.as_string() + b.as_string();
        default:
            throw kind_error(std::string("Invalid kind ") + to_string(a.kind()));
    }
}

value merge_explicit(const merge_rules&, const path&, value a)
{
    return a;
}

value merge_explicit(const merge_rules&, const path&)
{
    return object();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Diff                                                                                //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

diff_result diff(value left, value right)
{
    diff_result result;
    if (left == right)
    {
        result.same = std::move(left);
    }
    else if (left.kind() != right.kind())
    {
        result.left  = std::move(left);
        result.right = std::move(right);
    }
    else switch (left.kind())
    {
    case kind::boolean:
    case kind::decimal:
    case kind::integer:
    case kind::null:
    case kind::string:
        result.left = std::move(left);
        result.right = std::move(right);
        break;
    case kind::array:
        result.same = array();
        result.left = array();
        result.right = array();
        for (value::size_type idx = 0; idx < std::min(left.size(), right.size()); ++idx)
        {
            diff_result subresult = diff(std::move(left.at(idx)), std::move(right.at(idx)));
            result.same.push_back(std::move(subresult.same));
            result.left.push_back(std::move(subresult.left));
            result.right.push_back(std::move(subresult.right));
        }

        if (left.size() > right.size())
            result.left.insert(result.left.end_array(),
                               std::make_move_iterator(left.begin_array() + right.size()),
                               std::make_move_iterator(left.end_array())
                              );
        else if (left.size() < right.size())
            result.right.insert(result.right.end_array(),
                                std::make_move_iterator(right.begin_array() + left.size()),
                                std::make_move_iterator(right.end_array())
                               );
        break;
    case kind::object:
        result.same = object();
        result.left = object();
        result.right = object();
        for (value::object_iterator liter = left.begin_object();
             liter != left.end_object();
             liter = left.erase(liter)
            )
        {
            auto riter = right.find(liter->first);
            if (riter == right.end_object())
            {
                result.left.insert({ liter->first, std::move(liter->second) });
            }
            else if (liter->second == riter->second)
            {
                result.same[liter->first] = std::move(liter->second);
                right.erase(riter);
            }
            else
            {
                diff_result subresult = diff(std::move(liter->second), std::move(riter->second));
                result.left[liter->first] = std::move(subresult.left);
                result.right[liter->first] = std::move(subresult.right);
                right.erase(riter);
            }
        }

        for (value::object_iterator riter = right.begin_object();
             riter != right.end_object();
             riter = right.erase(riter)
            )
        {
            result.right.insert({ riter->first, std::move(riter->second) });
        }
        break;
    }
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Validation                                                                                //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static std::string validation_error_whatstring(validation_error::code code, const path& p, const value& elem)
{
    std::ostringstream ss;
    ss << "Validation error: Got " << code << " at path " << p << ": " << elem;
    return ss.str();
}

std::ostream& operator<<(std::ostream& os, const validation_error::code& code)
{
    switch (code)
    {
    case validation_error::code::non_finite_number: return os << "non-finite number";
    default:                                        return os << "validation_error::code(" << static_cast<int>(code) << ")";
    }
}

validation_error::validation_error(code code_, jsonv::path path_, jsonv::value value_) :
        runtime_error(validation_error_whatstring(code_, path_, value_)),
        _code(code_),
        _path(std::move(path_)),
        _value(std::move(value_))
{ }

validation_error::~validation_error() noexcept = default;

validation_error::code validation_error::error_code() const
{
    return _code;
}

const path& validation_error::path() const
{
    return _path;
}

const value& validation_error::value() const
{
    return _value;
}

void validate(const value& val)
{
    traverse(val,
             [] (const path& p, const value& elem)
             {
                 if (elem.kind() == kind::decimal)
                 {
                     if (!std::isfinite(elem.as_decimal()))
                         throw validation_error(validation_error::code::non_finite_number, p, elem);
                 }
             }
            );
}

}
<commit_msg>Changes the implementation of merge_explicit for objects to destroy the input while iterating it.<commit_after>/** \file
 *
 *  Copyright (c) 2015 by Travis Gockel. All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify it under the terms of the Apache License
 *  as published by the Apache Software Foundation, either version 2 of the License, or (at your option) any later
 *  version.
 *
 *  \author Travis Gockel (travis@gockelhut.com)
**/
#include <jsonv/util.hpp>
#include <jsonv/algorithm.hpp>
#include <jsonv/string_view.hpp>
#include <jsonv/coerce.hpp>

#include <sstream>
#include <stdexcept>

namespace jsonv
{

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Merging                                                                                //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

merge_rules::~merge_rules() noexcept = default;

dynamic_merge_rules::dynamic_merge_rules(same_key_function same_key, type_conflict_function type_conflict) :
        same_key(std::move(same_key)),
        type_conflict(std::move(type_conflict))
{ }

dynamic_merge_rules::~dynamic_merge_rules() noexcept = default;

value dynamic_merge_rules::resolve_same_key(path&& current_path, value&& a, value&& b) const
{
    return same_key(std::move(current_path), std::move(a), std::move(b));
}

value dynamic_merge_rules::resolve_type_conflict(path&& current_path, value&& a, value&& b) const
{
    return same_key(std::move(current_path), std::move(a), std::move(b));
}

value throwing_merge_rules::resolve_type_conflict(path&& current_path, value&& a, value&& b) const
{
    throw kind_error(std::string("Found different types at path `") + to_string(current_path) + "': "
                     + to_string(a.kind()) + " and " + to_string(b.kind()));
}

value throwing_merge_rules::resolve_same_key(path&& current_path, value&&, value&&) const
{
    throw std::logic_error(std::string("Cannot merge duplicate key at \"") + to_string(current_path) + "\"");
}

value recursive_merge_rules::resolve_same_key(path&& current_path, value&& a, value&& b) const
{
    return merge_explicit(*this, std::move(current_path), std::move(a), std::move(b));
}

value recursive_merge_rules::resolve_type_conflict(path&&, value&& a, value&& b) const
{
    return coerce_merge(std::move(a), std::move(b));
}

value merge_explicit(const merge_rules& rules,
                     path               current_path,
                     value              a,
                     value              b
                    )
{
    if (  a.kind() != b.kind()
       && !(   (a.kind() == kind::integer && b.kind() == kind::decimal)
            || (a.kind() == kind::decimal && b.kind() == kind::integer)
           )
       )
        return rules.resolve_type_conflict(std::move(current_path), std::move(a), std::move(b));

    switch (a.kind())
    {
        case kind::object:
        {
            value out = object();
            for (value::object_iterator iter = a.begin_object(); iter != a.end_object(); iter = a.erase(iter))
            {
                auto iter_b = b.find(iter->first);
                if (iter_b == b.end_object())
                {
                    out.insert({ iter->first, std::move(iter->second) });
                }
                else
                {
                    out.insert({ iter->first,
                                 rules.resolve_same_key(current_path + iter->first,
                                                        std::move(iter->second),
                                                        std::move(iter_b->second)
                                                       )
                               }
                              );
                    b.erase(iter_b);
                }
            }

            for (value::object_iterator iter = b.begin_object(); iter != b.end_object(); ++iter)
            {
                out.insert({ iter->first, std::move(iter->second) });
            }

            return out;
        }
        case kind::array:
            a.insert(a.end_array(), std::make_move_iterator(b.begin_array()), std::make_move_iterator(b.end_array()));
            return a;
        case kind::boolean:
            return a.as_boolean() || b.as_boolean();
        case kind::integer:
            if (b.kind() == kind::integer)
                return a.as_integer() + b.as_integer();
            // fall through to decimal handler if b is a decimal
        case kind::decimal:
            return a.as_decimal() + b.as_decimal();
        case kind::null:
            return a;
        case kind::string:
            return a.as_string() + b.as_string();
        default:
            throw kind_error(std::string("Invalid kind ") + to_string(a.kind()));
    }
}

value merge_explicit(const merge_rules&, const path&, value a)
{
    return a;
}

value merge_explicit(const merge_rules&, const path&)
{
    return object();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Diff                                                                                //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

diff_result diff(value left, value right)
{
    diff_result result;
    if (left == right)
    {
        result.same = std::move(left);
    }
    else if (left.kind() != right.kind())
    {
        result.left  = std::move(left);
        result.right = std::move(right);
    }
    else switch (left.kind())
    {
    case kind::boolean:
    case kind::decimal:
    case kind::integer:
    case kind::null:
    case kind::string:
        result.left = std::move(left);
        result.right = std::move(right);
        break;
    case kind::array:
        result.same = array();
        result.left = array();
        result.right = array();
        for (value::size_type idx = 0; idx < std::min(left.size(), right.size()); ++idx)
        {
            diff_result subresult = diff(std::move(left.at(idx)), std::move(right.at(idx)));
            result.same.push_back(std::move(subresult.same));
            result.left.push_back(std::move(subresult.left));
            result.right.push_back(std::move(subresult.right));
        }

        if (left.size() > right.size())
            result.left.insert(result.left.end_array(),
                               std::make_move_iterator(left.begin_array() + right.size()),
                               std::make_move_iterator(left.end_array())
                              );
        else if (left.size() < right.size())
            result.right.insert(result.right.end_array(),
                                std::make_move_iterator(right.begin_array() + left.size()),
                                std::make_move_iterator(right.end_array())
                               );
        break;
    case kind::object:
        result.same = object();
        result.left = object();
        result.right = object();
        for (value::object_iterator liter = left.begin_object();
             liter != left.end_object();
             liter = left.erase(liter)
            )
        {
            auto riter = right.find(liter->first);
            if (riter == right.end_object())
            {
                result.left.insert({ liter->first, std::move(liter->second) });
            }
            else if (liter->second == riter->second)
            {
                result.same[liter->first] = std::move(liter->second);
                right.erase(riter);
            }
            else
            {
                diff_result subresult = diff(std::move(liter->second), std::move(riter->second));
                result.left[liter->first] = std::move(subresult.left);
                result.right[liter->first] = std::move(subresult.right);
                right.erase(riter);
            }
        }

        for (value::object_iterator riter = right.begin_object();
             riter != right.end_object();
             riter = right.erase(riter)
            )
        {
            result.right.insert({ riter->first, std::move(riter->second) });
        }
        break;
    }
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Validation                                                                                //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static std::string validation_error_whatstring(validation_error::code code, const path& p, const value& elem)
{
    std::ostringstream ss;
    ss << "Validation error: Got " << code << " at path " << p << ": " << elem;
    return ss.str();
}

std::ostream& operator<<(std::ostream& os, const validation_error::code& code)
{
    switch (code)
    {
    case validation_error::code::non_finite_number: return os << "non-finite number";
    default:                                        return os << "validation_error::code(" << static_cast<int>(code) << ")";
    }
}

validation_error::validation_error(code code_, jsonv::path path_, jsonv::value value_) :
        runtime_error(validation_error_whatstring(code_, path_, value_)),
        _code(code_),
        _path(std::move(path_)),
        _value(std::move(value_))
{ }

validation_error::~validation_error() noexcept = default;

validation_error::code validation_error::error_code() const
{
    return _code;
}

const path& validation_error::path() const
{
    return _path;
}

const value& validation_error::value() const
{
    return _value;
}

void validate(const value& val)
{
    traverse(val,
             [] (const path& p, const value& elem)
             {
                 if (elem.kind() == kind::decimal)
                 {
                     if (!std::isfinite(elem.as_decimal()))
                         throw validation_error(validation_error::code::non_finite_number, p, elem);
                 }
             }
            );
}

}
<|endoftext|>


<commit_before>//  =============== BEGIN ASSESSMENT HEADER ================
/// @file Assignment 2/Executable.cpp
/// @author <Haripriya Vasireddy> [hvasi001@ucr.edu]
/// @date <April 30, 2016>
//  ================== END ASSESSMENT HEADER ===============

#include "Executable.h"
#include "LeafCommand.h"
#include <signal.h>
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <sys/wait.h>
#include <cerrno>
using namespace std;
//Destructor
Executable::~Executable(){}

int Executable::execute(Command *c)
{
    //errno = 0;
    char **arg = new char*[static_cast<LeafCommand*>(c)->argList->size() + 1];
    copy(static_cast<LeafCommand*>(c)->argList->begin(), static_cast<LeafCommand*>(c)->argList->end(), arg);
    arg[static_cast<LeafCommand*>(c)->argList->size()] = '\0';

    pid_t pid;
    int status;

    //fork
    pid = fork();
    if (pid < 0) //fork failure
        ;
    else if (pid == 0) //child process
        execvp(*arg, arg);
    else //parent waiting for the child
        waitpid(pid, &status, 0);

    return status;
}<commit_msg>Modified to give error message for unrecognized commands<commit_after>//  =============== BEGIN ASSESSMENT HEADER ================
/// @file Assignment 2/Executable.cpp
/// @author <Haripriya Vasireddy> [hvasi001@ucr.edu]
/// @date <April 30, 2016>
//  ================== END ASSESSMENT HEADER ===============

#include "Executable.h"
#include "LeafCommand.h"
#include <signal.h>
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <sys/wait.h>
#include <cerrno>
using namespace std;
//Destructor
Executable::~Executable(){}

int Executable::execute(Command *c)
{
    //errno = 0;
    int evp_status;
    char **arg = new char*[static_cast<LeafCommand*>(c)->argList->size() + 1];
    copy(static_cast<LeafCommand*>(c)->argList->begin(), static_cast<LeafCommand*>(c)->argList->end(), arg);
    arg[static_cast<LeafCommand*>(c)->argList->size()] = '\0';

    pid_t pid;
    int status;

    //fork
    pid = fork();
    if (pid < 0) //fork failure
        ;
    else if (pid == 0) //child process
    {
        evp_status = execvp(*arg, arg);
        if(evp_status == -1)
        {
            cout << "command not found" << endl;
        }
    }
    else //parent waiting for the child
        waitpid(pid, &status, 0);

    return status;
}<|endoftext|>


<commit_before>#include <GLUI/GLUI.h>
#include <GLUIExt.h>

namespace glui {
	namespace input {
		std::string* Input::textString = 0;
		size_t Input::textInsertPoint = 0;
		int Input::mousePosx = -1;
		int Input::mousePosy = -1;
		bool Input::mouseLeftDown = false;
		unsigned char* Input::keys = new unsigned char[GLFW_KEY_LAST];

		void Input::init() {
			memset(Input::keys, 0, sizeof(unsigned char) * GLFW_KEY_LAST);
		}

		void callbacks::mousePosition(int posx, int posy) {
			Input::mousePosx = posx;
			Input::mousePosy = posy;
		}

		void callbacks::mouseButton(int button, int state) {
			if (button == GLFW_MOUSE_BUTTON_LEFT) {
				if (state == GLFW_PRESS) {
					Input::mouseLeftDown = true;
				}
				else if (state == GLFW_RELEASE) {
					Input::mouseLeftDown = false;
				}
			}

		}

		void callbacks::key(int key, int state) {
			Input::keys[key] = state;
			if (Input::textString != 0 && key == GLFW_KEY_BACKSPACE && state == GLFW_PRESS && Input::textString->size() != 0) {
				Input::textString->replace(Input::textInsertPoint-1, 1, "");
			}
		}

		void callbacks::text(unsigned int codepoint) {
			if (Input::textString != 0) {
				char car = (char) codepoint;
				Input::textString->insert(Input::textInsertPoint, std::string(&car));
			}
		}

		void keyboard::setTextCallback(std::string* string) {
			Input::textString = string;
		}

		void keyboard::setTextInsertPoint(size_t index) {
			Input::textInsertPoint = index;
		}
	}
}<commit_msg>fixed mac textbox bug<commit_after>#include <GLUI/GLUI.h>
#include <GLUIExt.h>

namespace glui {
	namespace input {
		std::string* Input::textString = 0;
		size_t Input::textInsertPoint = 0;
		int Input::mousePosx = -1;
		int Input::mousePosy = -1;
		bool Input::mouseLeftDown = false;
		unsigned char* Input::keys = new unsigned char[GLFW_KEY_LAST];

		void Input::init() {
			memset(Input::keys, 0, sizeof(unsigned char) * GLFW_KEY_LAST);
		}

		void callbacks::mousePosition(int posx, int posy) {
			Input::mousePosx = posx;
			Input::mousePosy = posy;
		}

		void callbacks::mouseButton(int button, int state) {
			if (button == GLFW_MOUSE_BUTTON_LEFT) {
				if (state == GLFW_PRESS) {
					Input::mouseLeftDown = true;
				}
				else if (state == GLFW_RELEASE) {
					Input::mouseLeftDown = false;
				}
			}

		}

		void callbacks::key(int key, int state) {
			Input::keys[key] = state;
			if (Input::textString != 0 && key == GLFW_KEY_BACKSPACE && state == GLFW_PRESS && Input::textString->size() != 0) {
				Input::textString->replace(Input::textInsertPoint-1, 1, "");
			}
		}

		void callbacks::text(unsigned int codepoint) {
			if (Input::textString != 0) {
				char* insertion = new char[1];
				insertion[0] = (char) codepoint;
				Input::textString->insert(Input::textInsertPoint, std::string(insertion));
			}
		}

		void keyboard::setTextCallback(std::string* string) {
			Input::textString = string;
		}

		void keyboard::setTextInsertPoint(size_t index) {
			Input::textInsertPoint = index;
		}
	}
}<|endoftext|>


<commit_before>#ifndef DEF_LAMBDARANK_H
#define DEF_LAMBDARANK_H
/**
 * @file
 * @author  David Nemeskey
 * @version 0.1
 *
 * @section LICENSE
 *
 * Copyright [2013] [MTA SZTAKI]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The LambdaRank algorithm. Since it is very closely related to RankNet, we
 * derive it from that class.
 */

#include <cmath>

#include "ranknet_lambda.hpp"
#include "lambdarank_optimize.hpp"

class LambdaRank : public RankNetLambda {
public:
  /** @param[in] sigma parameter of the sigmoid. */
  LambdaRank(MlModel* model, EvaluationMeasure* eval,
             StoppingCondition stop, LtrRunningPhase phase=TRAINING,
             double sigma=1)
      : RankNetLambda(model, eval, stop, phase, sigma) {
  }

  /****************************** GraphChi stuff ******************************/

  /** The actual RankNet implementation. */
  virtual void compute_gradients(
      graphchi_vertex<TypeVertex, FeatureEdge> &query, Gradient* umodel) {
    std::vector<double> lambdas(query.num_outedges());
    std::vector<double> s_is(query.num_outedges());

    /* First, we compute all the outputs... */
    for (int i = 0; i < query.num_outedges(); i++) {
      s_is[i] = get_score(query.outedge(i));
//      std::cout << "s[" << i << "] == " << s_is[i] << std::endl;
    }
    /* ...and the retrieval measure scores. */
    opt.compute(query);

    /* Now, we compute the errors (lambdas). */
    for (int i = 0; i < query.num_outedges() - 1; i++) {
      int rel_i = get_relevance(query.outedge(i));
      for (int j = i + 1; j < query.num_outedges(); j++) {
        int rel_j = get_relevance(query.outedge(j));
        if (rel_i != rel_j) {
          double S_ij = rel_i > rel_j ? 1 : -1;
          double lambda_ij = dC_per_ds_i(S_ij, s_is[i], s_is[j]) *
                             fabs(opt.delta(query, i, j));
          /* lambda_ij = -lambda_ji */
          lambdas[i] += lambda_ij;
          lambdas[j] -= lambda_ij;
        }
      }
    }

    /* Finally, the model update. */
    for (int i = 0; i < query.num_outedges(); i++) {
      // -lambdas[i], as C is a utility function in this case
      umodel->update(query.outedge(i)->get_vector()->get_data(), s_is[i], lambdas[i]);
    }
  }

private:
  /**
   * The information retrieval measure we are optimizing for.
   * @todo add more measures.
   */
  NdcgOptimizer opt;
};

#endif
<commit_msg>Cosmetic change in method docstring. 	modified:   src/lambdarank.hpp<commit_after>#ifndef DEF_LAMBDARANK_H
#define DEF_LAMBDARANK_H
/**
 * @file
 * @author  David Nemeskey
 * @version 0.1
 *
 * @section LICENSE
 *
 * Copyright [2013] [MTA SZTAKI]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The LambdaRank algorithm. Since it is very closely related to RankNet, we
 * derive it from that class.
 */

#include <cmath>

#include "ranknet_lambda.hpp"
#include "lambdarank_optimize.hpp"

class LambdaRank : public RankNetLambda {
public:
  /** @param[in] sigma parameter of the sigmoid. */
  LambdaRank(MlModel* model, EvaluationMeasure* eval,
             StoppingCondition stop, LtrRunningPhase phase=TRAINING,
             double sigma=1)
      : RankNetLambda(model, eval, stop, phase, sigma) {
  }

  /****************************** GraphChi stuff ******************************/

  /** The actual LambdaRank implementation. */
  virtual void compute_gradients(
      graphchi_vertex<TypeVertex, FeatureEdge> &query, Gradient* umodel) {
    std::vector<double> lambdas(query.num_outedges());
    std::vector<double> s_is(query.num_outedges());

    /* First, we compute all the outputs... */
    for (int i = 0; i < query.num_outedges(); i++) {
      s_is[i] = get_score(query.outedge(i));
//      std::cout << "s[" << i << "] == " << s_is[i] << std::endl;
    }
    /* ...and the retrieval measure scores. */
    opt.compute(query);

    /* Now, we compute the errors (lambdas). */
    for (int i = 0; i < query.num_outedges() - 1; i++) {
      int rel_i = get_relevance(query.outedge(i));
      for (int j = i + 1; j < query.num_outedges(); j++) {
        int rel_j = get_relevance(query.outedge(j));
        if (rel_i != rel_j) {
          double S_ij = rel_i > rel_j ? 1 : -1;
          double lambda_ij = dC_per_ds_i(S_ij, s_is[i], s_is[j]) *
                             fabs(opt.delta(query, i, j));
          /* lambda_ij = -lambda_ji */
          lambdas[i] += lambda_ij;
          lambdas[j] -= lambda_ij;
        }
      }
    }

    /* Finally, the model update. */
    for (int i = 0; i < query.num_outedges(); i++) {
      // -lambdas[i], as C is a utility function in this case
      umodel->update(query.outedge(i)->get_vector()->get_data(), s_is[i], lambdas[i]);
    }
  }

private:
  /**
   * The information retrieval measure we are optimizing for.
   * @todo add more measures.
   */
  NdcgOptimizer opt;
};

#endif
<|endoftext|>


<commit_before>#include "Game/Piece.h"

#include <cctype>
#include <algorithm>
#include <cassert>
#include <array>
#include <cctype>

#include "Game/Square.h"
#include "Game/Color.h"

#include "Moves/Move.h"
#include "Moves/Direction.h"
#include "Moves/Pawn_Move.h"
#include "Moves/Pawn_Double_Move.h"
#include "Moves/Pawn_Promotion.h"
#include "Moves/En_Passant.h"
#include "Moves/Castle.h"

#include "Utility/Fixed_Capacity_Vector.h"

const Piece::piece_code_t Piece::invalid_code = Piece{Piece_Color::BLACK, Piece_Type::KING}.index() + 1;

namespace
{
    const std::string pgn_symbols = "PRNBQK";

    using indexed_move_array = std::array<std::array<Fixed_Capacity_Vector<Fixed_Capacity_Vector<const Move*, 7>, 12>, 64>, 12>;

    void add_pawn_moves(indexed_move_array& out, Piece_Color color) noexcept;
    void add_rook_moves(indexed_move_array& out, Piece_Color color, Piece_Type type = Piece_Type::ROOK) noexcept;
    void add_knight_moves(indexed_move_array& out, Piece_Color color) noexcept;
    void add_bishop_moves(indexed_move_array& out, Piece_Color color, Piece_Type type = Piece_Type::BISHOP) noexcept;
    void add_queen_moves(indexed_move_array& out, Piece_Color color) noexcept;
    void add_king_moves(indexed_move_array& out, Piece_Color color) noexcept;

    const auto legal_moves =
        []()
        {
            indexed_move_array result;
            for(auto color : {Piece_Color::WHITE, Piece_Color::BLACK})
            {
                add_pawn_moves(result, color);
                add_rook_moves(result, color);
                add_knight_moves(result, color);
                add_bishop_moves(result, color);
                add_queen_moves(result, color);
                add_king_moves(result, color);
            }

            return result;
        }();

    const auto attack_moves =
        []()
        {
            indexed_move_array result;
            for(auto color : {Piece_Color::WHITE, Piece_Color::BLACK})
            {
                for(auto type : {Piece_Type::PAWN, Piece_Type::ROOK, Piece_Type::KNIGHT, Piece_Type::BISHOP, Piece_Type::QUEEN, Piece_Type::KING})
                {
                    auto piece = Piece{color, type};
                    for(size_t index = 0; index < 64; ++index)
                    {
                        for(const auto& move_list : legal_moves[piece.index()][index])
                        {
                            result[piece.index()][index].push_back({});

                            for(auto move : move_list)
                            {
                                // Make list of all capturing moves, excluding all but one type of pawn capture per square.
                                if(move->can_capture()
                                    && ! move->is_en_passant()
                                    && (move->promotion_piece_symbol() == 'Q' || move->promotion_piece_symbol() == '\0'))
                                {
                                    result[piece.index()][index].back().push_back(move);
                                }
                            }
                        }
                    }
                }
            }

            return result;
        }();

    // Add a move to the list that is only legal when starting from a certain square
    // (e.g., castling, pawn double move, promotion, etc.)
    template<typename Move_Type, typename ...Parameters>
    void add_legal_move(indexed_move_array& out, Piece piece, bool blockable, Parameters ... parameters) noexcept
    {
        auto move = new Move_Type(parameters...);
        auto& lists = out[piece.index()][move->start().index()];
        if(lists.empty() || ! blockable)
        {
            lists.push_back({});
        }

        if( ! lists.back().empty() && ! same_direction(move->movement(), lists.back().back()->movement()))
        {
            lists.push_back({});
        }

        lists.back().push_back(move);
    }

    void add_standard_legal_move(indexed_move_array& out, Piece piece, int file_step, int rank_step, bool blockable) noexcept
    {
        for(auto start : Square::all_squares())
        {
            auto end = start + Square_Difference{file_step, rank_step};
            if(end.inside_board())
            {
                add_legal_move<Move>(out, piece, blockable, start, end);
            }
        }
    }

    void add_pawn_moves(indexed_move_array& out, Piece_Color color) noexcept
    {
        auto pawn = Piece{color, Piece_Type::PAWN};
        auto base_rank = (color == Piece_Color::WHITE ? 2 : 7);
        auto no_normal_move_rank = (color == Piece_Color::WHITE ? 7 : 2);
        auto rank_change = (color == Piece_Color::WHITE ? 1 : -1);
        for(char file = 'a'; file <= 'h'; ++file)
        {
            for(int rank = base_rank; rank != no_normal_move_rank; rank += rank_change)
            {
                add_legal_move<Pawn_Move>(out, pawn, true, color, Square{file, rank});
            }
        }

        for(char file = 'a'; file <= 'h'; ++file)
        {
            add_legal_move<Pawn_Double_Move>(out, pawn, true, color, file);
        }

        auto possible_promotions = {Piece_Type::QUEEN, Piece_Type::KNIGHT, Piece_Type::ROOK, Piece_Type::BISHOP};

        for(auto dir : {Direction::RIGHT, Direction::LEFT})
        {
            auto first_file = (dir == Direction::RIGHT ? 'a' : 'b');
            auto last_file = (dir == Direction::RIGHT ? 'g' : 'h');
            for(char file = first_file; file <= last_file; ++file)
            {
                for(int rank = base_rank; rank != no_normal_move_rank; rank += rank_change)
                {
                    add_legal_move<Pawn_Move>(out, pawn, true, color, Square{file, rank}, dir);
                }
            }

            for(char file = first_file; file <= last_file; ++file)
            {
                add_legal_move<En_Passant>(out, pawn, true, color, dir, file);
            }

            for(auto promote : possible_promotions)
            {
                for(auto file = first_file; file <= last_file; ++file)
                {
                    add_legal_move<Pawn_Promotion>(out, pawn, false, promote, color, file, dir);
                }
            }
        }

        for(auto promote : possible_promotions)
        {
            for(auto file = 'a'; file <= 'h'; ++file)
            {
                add_legal_move<Pawn_Promotion>(out, pawn, false, promote, color, file);
            }
        }
    }

    void add_rook_moves(indexed_move_array& out, Piece_Color color, Piece_Type type) noexcept
    {
        for(int d_file = -1; d_file <= 1; ++d_file)
        {
            for(int d_rank = -1; d_rank <= 1; ++d_rank)
            {
                if(d_file == 0 && d_rank == 0) { continue; }
                if(d_file != 0 && d_rank != 0) { continue; }

                for(int move_size = 1; move_size <= 7; ++move_size)
                {
                    add_standard_legal_move(out, {color, type}, move_size*d_file, move_size*d_rank, true);
                }
            }
        }
    }

    void add_knight_moves(indexed_move_array& out, Piece_Color color) noexcept
    {
        for(auto d_file : {1, 2})
        {
            auto d_rank = 3 - d_file;
            for(auto file_direction : {-1, 1})
            {
                for(auto rank_direction : {-1, 1})
                {
                    add_standard_legal_move(out, {color, Piece_Type::KNIGHT}, d_file*file_direction, d_rank*rank_direction, false);
                }
            }
        }
    }

    void add_bishop_moves(indexed_move_array& out, Piece_Color color, Piece_Type type) noexcept
    {
        for(int d_rank : {-1, 1})
        {
            for(int d_file : {-1, 1})
            {
                for(int move_size = 1; move_size <= 7; ++move_size)
                {
                    add_standard_legal_move(out, {color, type}, move_size*d_file, move_size*d_rank, true);
                }
            }
        }
    }

    void add_queen_moves(indexed_move_array& out, Piece_Color color) noexcept
    {
        add_bishop_moves(out, color, Piece_Type::QUEEN);
        add_rook_moves(out, color, Piece_Type::QUEEN);
    }

    void add_king_moves(indexed_move_array& out, Piece_Color color) noexcept
    {
        auto king = Piece{color, Piece_Type::KING};
        auto kingside_castle_added = false;
        auto queenside_castle_added = false;
        int base_rank = (color == Piece_Color::WHITE ? 1 : 8);
        for(int d_rank = -1; d_rank <= 1; ++d_rank)
        {
            for(int d_file = -1; d_file <= 1; ++d_file)
            {
                if(d_rank == 0 && d_file == 0) { continue; }

                add_standard_legal_move(out, king, d_file, d_rank, true);
                if(d_rank == 0)
                {
                    if(d_file > 0)
                    {
                        if( ! kingside_castle_added)
                        {
                            add_legal_move<Castle>(out, king, true, base_rank, Direction::RIGHT);
                            kingside_castle_added = true;
                        }
                    }
                    else
                    {
                        if( ! queenside_castle_added)
                        {
                            add_legal_move<Castle>(out, king, true, base_rank, Direction::LEFT);
                        }
                    }
                }
            }
        }
    }

    Piece_Type piece_type_from_char(char pgn_symbol)
    {
        auto i = pgn_symbols.find(std::toupper(pgn_symbol));
        if(i == std::string::npos)
        {
            throw std::invalid_argument(pgn_symbol + std::string{" is not a valid piece PGN symbol."});
        }
        return static_cast<Piece_Type>(i);
    }
}

Piece::Piece() noexcept : piece_code(invalid_code)
{
}

Piece::Piece(Piece_Color color, Piece_Type type) noexcept :
    piece_code((static_cast<int>(type) << 1) | static_cast<int>(color))
{
    // piece_code layout: 4 bits
    // 3 most significant bits = Piece_Type (values 0-5)
    // least significant bit = Piece_Color (0 or 1)
    //
    // 101 1
    // ^^^ ^-- Piece_Color::BLACK
    //  +--- Piece_Type::KING
}

Piece::Piece(char pgn_symbol) : Piece(std::isupper(pgn_symbol) ? Piece_Color::WHITE : Piece_Color::BLACK,
                                      piece_type_from_char(pgn_symbol))
{
}

Piece_Color Piece::color() const noexcept
{
    assert(*this);
    return static_cast<Piece_Color>(piece_code & 1);
}

std::string Piece::pgn_symbol() const noexcept
{
    assert(*this);
    return type() == Piece_Type::PAWN ? std::string{} : std::string(1, std::toupper(fen_symbol()));
}

char Piece::fen_symbol() const noexcept
{
    assert(*this);
    auto symbol = pgn_symbols[static_cast<int>(type())];
    return (color() == Piece_Color::WHITE ? symbol : std::tolower(symbol));
}

bool Piece::can_move(const Move* move) const noexcept
{
    assert(*this);
    for(const auto& moves : move_lists(move->start()))
    {
        if(std::find(moves.begin(), moves.end(), move) != moves.end())
        {
            return true;
        }
    }

    return false;
}

const Piece::list_of_move_lists& Piece::move_lists(Square square) const noexcept
{
    assert(*this);
    return legal_moves[index()][square.index()];
}

Piece_Type Piece::type() const noexcept
{
    assert(*this);
    return static_cast<Piece_Type>(piece_code >> 1);
}

Piece::operator bool() const noexcept
{
    return piece_code != invalid_code;
}

Piece::piece_code_t Piece::index() const noexcept
{
    return piece_code;
}

const Piece::list_of_move_lists& Piece::attacking_move_lists(Square square) const noexcept
{
    assert(*this);
    return attack_moves[index()][square.index()];
}

bool operator==(Piece a, Piece b) noexcept
{
    return a.index() == b.index();
}

bool operator!=(Piece a, Piece b) noexcept
{
    return !(a == b);
}
<commit_msg>Iterate through Pieces instead of listing them<commit_after>#include "Game/Piece.h"

#include <cctype>
#include <algorithm>
#include <cassert>
#include <array>
#include <cctype>

#include "Game/Square.h"
#include "Game/Color.h"

#include "Moves/Move.h"
#include "Moves/Direction.h"
#include "Moves/Pawn_Move.h"
#include "Moves/Pawn_Double_Move.h"
#include "Moves/Pawn_Promotion.h"
#include "Moves/En_Passant.h"
#include "Moves/Castle.h"

#include "Utility/Fixed_Capacity_Vector.h"

const Piece::piece_code_t Piece::invalid_code = Piece{Piece_Color::BLACK, Piece_Type::KING}.index() + 1;

namespace
{
    const std::string pgn_symbols = "PRNBQK";

    using indexed_move_array = std::array<std::array<Fixed_Capacity_Vector<Fixed_Capacity_Vector<const Move*, 7>, 12>, 64>, 12>;

    void add_pawn_moves(indexed_move_array& out, Piece_Color color) noexcept;
    void add_rook_moves(indexed_move_array& out, Piece_Color color, Piece_Type type = Piece_Type::ROOK) noexcept;
    void add_knight_moves(indexed_move_array& out, Piece_Color color) noexcept;
    void add_bishop_moves(indexed_move_array& out, Piece_Color color, Piece_Type type = Piece_Type::BISHOP) noexcept;
    void add_queen_moves(indexed_move_array& out, Piece_Color color) noexcept;
    void add_king_moves(indexed_move_array& out, Piece_Color color) noexcept;

    const auto legal_moves =
        []()
        {
            indexed_move_array result;
            for(auto color : {Piece_Color::WHITE, Piece_Color::BLACK})
            {
                add_pawn_moves(result, color);
                add_rook_moves(result, color);
                add_knight_moves(result, color);
                add_bishop_moves(result, color);
                add_queen_moves(result, color);
                add_king_moves(result, color);
            }

            return result;
        }();

    const auto attack_moves =
        []()
        {
            indexed_move_array result;
            for(auto color : {Piece_Color::WHITE, Piece_Color::BLACK})
            {
                for(auto type_index = 0; type_index <= static_cast<int>(Piece_Type::KING); ++type_index)
                {
                    auto piece = Piece{color, static_cast<Piece_Type>(type_index)};
                    for(size_t index = 0; index < 64; ++index)
                    {
                        for(const auto& move_list : legal_moves[piece.index()][index])
                        {
                            result[piece.index()][index].push_back({});

                            for(auto move : move_list)
                            {
                                // Make list of all capturing moves, excluding all but one type of pawn capture per square.
                                if(move->can_capture()
                                    && ! move->is_en_passant()
                                    && (move->promotion_piece_symbol() == 'Q' || move->promotion_piece_symbol() == '\0'))
                                {
                                    result[piece.index()][index].back().push_back(move);
                                }
                            }
                        }
                    }
                }
            }

            return result;
        }();

    // Add a move to the list that is only legal when starting from a certain square
    // (e.g., castling, pawn double move, promotion, etc.)
    template<typename Move_Type, typename ...Parameters>
    void add_legal_move(indexed_move_array& out, Piece piece, bool blockable, Parameters ... parameters) noexcept
    {
        auto move = new Move_Type(parameters...);
        auto& lists = out[piece.index()][move->start().index()];
        if(lists.empty() || ! blockable)
        {
            lists.push_back({});
        }

        if( ! lists.back().empty() && ! same_direction(move->movement(), lists.back().back()->movement()))
        {
            lists.push_back({});
        }

        lists.back().push_back(move);
    }

    void add_standard_legal_move(indexed_move_array& out, Piece piece, int file_step, int rank_step, bool blockable) noexcept
    {
        for(auto start : Square::all_squares())
        {
            auto end = start + Square_Difference{file_step, rank_step};
            if(end.inside_board())
            {
                add_legal_move<Move>(out, piece, blockable, start, end);
            }
        }
    }

    void add_pawn_moves(indexed_move_array& out, Piece_Color color) noexcept
    {
        auto pawn = Piece{color, Piece_Type::PAWN};
        auto base_rank = (color == Piece_Color::WHITE ? 2 : 7);
        auto no_normal_move_rank = (color == Piece_Color::WHITE ? 7 : 2);
        auto rank_change = (color == Piece_Color::WHITE ? 1 : -1);
        for(char file = 'a'; file <= 'h'; ++file)
        {
            for(int rank = base_rank; rank != no_normal_move_rank; rank += rank_change)
            {
                add_legal_move<Pawn_Move>(out, pawn, true, color, Square{file, rank});
            }
        }

        for(char file = 'a'; file <= 'h'; ++file)
        {
            add_legal_move<Pawn_Double_Move>(out, pawn, true, color, file);
        }

        std::vector<Piece_Type> possible_promotions;
        for(auto type_index = 0; type_index <= static_cast<int>(Piece_Type::KING); ++type_index)
        {
            auto type = static_cast<Piece_Type>(type_index);
            if(type == Piece_Type::PAWN || type == Piece_Type::KING)
            {
                continue;
            }
            possible_promotions.push_back(type);
        }

        for(auto dir : {Direction::RIGHT, Direction::LEFT})
        {
            auto first_file = (dir == Direction::RIGHT ? 'a' : 'b');
            auto last_file = (dir == Direction::RIGHT ? 'g' : 'h');
            for(char file = first_file; file <= last_file; ++file)
            {
                for(int rank = base_rank; rank != no_normal_move_rank; rank += rank_change)
                {
                    add_legal_move<Pawn_Move>(out, pawn, true, color, Square{file, rank}, dir);
                }
            }

            for(char file = first_file; file <= last_file; ++file)
            {
                add_legal_move<En_Passant>(out, pawn, true, color, dir, file);
            }

            for(auto promote : possible_promotions)
            {
                for(auto file = first_file; file <= last_file; ++file)
                {
                    add_legal_move<Pawn_Promotion>(out, pawn, false, promote, color, file, dir);
                }
            }
        }

        for(auto promote : possible_promotions)
        {
            for(auto file = 'a'; file <= 'h'; ++file)
            {
                add_legal_move<Pawn_Promotion>(out, pawn, false, promote, color, file);
            }
        }
    }

    void add_rook_moves(indexed_move_array& out, Piece_Color color, Piece_Type type) noexcept
    {
        for(int d_file = -1; d_file <= 1; ++d_file)
        {
            for(int d_rank = -1; d_rank <= 1; ++d_rank)
            {
                if(d_file == 0 && d_rank == 0) { continue; }
                if(d_file != 0 && d_rank != 0) { continue; }

                for(int move_size = 1; move_size <= 7; ++move_size)
                {
                    add_standard_legal_move(out, {color, type}, move_size*d_file, move_size*d_rank, true);
                }
            }
        }
    }

    void add_knight_moves(indexed_move_array& out, Piece_Color color) noexcept
    {
        for(auto d_file : {1, 2})
        {
            auto d_rank = 3 - d_file;
            for(auto file_direction : {-1, 1})
            {
                for(auto rank_direction : {-1, 1})
                {
                    add_standard_legal_move(out, {color, Piece_Type::KNIGHT}, d_file*file_direction, d_rank*rank_direction, false);
                }
            }
        }
    }

    void add_bishop_moves(indexed_move_array& out, Piece_Color color, Piece_Type type) noexcept
    {
        for(int d_rank : {-1, 1})
        {
            for(int d_file : {-1, 1})
            {
                for(int move_size = 1; move_size <= 7; ++move_size)
                {
                    add_standard_legal_move(out, {color, type}, move_size*d_file, move_size*d_rank, true);
                }
            }
        }
    }

    void add_queen_moves(indexed_move_array& out, Piece_Color color) noexcept
    {
        add_bishop_moves(out, color, Piece_Type::QUEEN);
        add_rook_moves(out, color, Piece_Type::QUEEN);
    }

    void add_king_moves(indexed_move_array& out, Piece_Color color) noexcept
    {
        auto king = Piece{color, Piece_Type::KING};
        auto kingside_castle_added = false;
        auto queenside_castle_added = false;
        int base_rank = (color == Piece_Color::WHITE ? 1 : 8);
        for(int d_rank = -1; d_rank <= 1; ++d_rank)
        {
            for(int d_file = -1; d_file <= 1; ++d_file)
            {
                if(d_rank == 0 && d_file == 0) { continue; }

                add_standard_legal_move(out, king, d_file, d_rank, true);
                if(d_rank == 0)
                {
                    if(d_file > 0)
                    {
                        if( ! kingside_castle_added)
                        {
                            add_legal_move<Castle>(out, king, true, base_rank, Direction::RIGHT);
                            kingside_castle_added = true;
                        }
                    }
                    else
                    {
                        if( ! queenside_castle_added)
                        {
                            add_legal_move<Castle>(out, king, true, base_rank, Direction::LEFT);
                        }
                    }
                }
            }
        }
    }

    Piece_Type piece_type_from_char(char pgn_symbol)
    {
        auto i = pgn_symbols.find(std::toupper(pgn_symbol));
        if(i == std::string::npos)
        {
            throw std::invalid_argument(pgn_symbol + std::string{" is not a valid piece PGN symbol."});
        }
        return static_cast<Piece_Type>(i);
    }
}

Piece::Piece() noexcept : piece_code(invalid_code)
{
}

Piece::Piece(Piece_Color color, Piece_Type type) noexcept :
    piece_code((static_cast<int>(type) << 1) | static_cast<int>(color))
{
    // piece_code layout: 4 bits
    // 3 most significant bits = Piece_Type (values 0-5)
    // least significant bit = Piece_Color (0 or 1)
    //
    // 101 1
    // ^^^ ^-- Piece_Color::BLACK
    //  +--- Piece_Type::KING
}

Piece::Piece(char pgn_symbol) : Piece(std::isupper(pgn_symbol) ? Piece_Color::WHITE : Piece_Color::BLACK,
                                      piece_type_from_char(pgn_symbol))
{
}

Piece_Color Piece::color() const noexcept
{
    assert(*this);
    return static_cast<Piece_Color>(piece_code & 1);
}

std::string Piece::pgn_symbol() const noexcept
{
    assert(*this);
    return type() == Piece_Type::PAWN ? std::string{} : std::string(1, std::toupper(fen_symbol()));
}

char Piece::fen_symbol() const noexcept
{
    assert(*this);
    auto symbol = pgn_symbols[static_cast<int>(type())];
    return (color() == Piece_Color::WHITE ? symbol : std::tolower(symbol));
}

bool Piece::can_move(const Move* move) const noexcept
{
    assert(*this);
    for(const auto& moves : move_lists(move->start()))
    {
        if(std::find(moves.begin(), moves.end(), move) != moves.end())
        {
            return true;
        }
    }

    return false;
}

const Piece::list_of_move_lists& Piece::move_lists(Square square) const noexcept
{
    assert(*this);
    return legal_moves[index()][square.index()];
}

Piece_Type Piece::type() const noexcept
{
    assert(*this);
    return static_cast<Piece_Type>(piece_code >> 1);
}

Piece::operator bool() const noexcept
{
    return piece_code != invalid_code;
}

Piece::piece_code_t Piece::index() const noexcept
{
    return piece_code;
}

const Piece::list_of_move_lists& Piece::attacking_move_lists(Square square) const noexcept
{
    assert(*this);
    return attack_moves[index()][square.index()];
}

bool operator==(Piece a, Piece b) noexcept
{
    return a.index() == b.index();
}

bool operator!=(Piece a, Piece b) noexcept
{
    return !(a == b);
}
<|endoftext|>


<commit_before>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_PROFILER_HH_INCLUDED
#define DUNE_STUFF_PROFILER_HH_INCLUDED

#ifndef DUNE_STUFF_ENABLE_PROFILE_SCOPE
# define DUNE_STUFF_ENABLE_PROFILE_SCOPE 0
#endif

#include <string>
#include <map>
#include <vector>
#include <ctime>
#include <memory>
#include <iostream>
#include <mutex>

#include <boost/noncopyable.hpp>
#include <boost/timer/timer.hpp>

#include <dune/common/unused.hh>

#include <dune/stuff/common/parallel/threadmanager.hh>
#include <dune/stuff/common/parallel/threadstorage.hh>

namespace Dune {
namespace Stuff {
namespace Common {

class Profiler;

//! Stuff::Profiler global instance
Profiler& profiler();

//! wraps name, start- and end time for one timing section
struct TimingData
{
private:
  std::shared_ptr<boost::timer::cpu_timer> timer_;
public:
  std::string name;

  explicit TimingData(const std::string _name = "blank");

  void stop();

  typedef boost::timer::nanosecond_type TimeType;
  typedef std::array<TimeType, 4> DeltaType;

  /** \return time elapsed since object construction in milliseconds
   *  \note since typical resolutions for user+system time are 10-15ms the nanosecond results are scaled accordingly
   **/
  DeltaType delta() const;
};

//! a utility class to time a limited scope of code
class ScopedTiming;

/** \brief simple inline profiling class
   *  - User can set as many (even nested) named sections whose total (=system+user) time will be computed across all program
   * instances.\n
   *  - Provides csv-conform output of process-averaged runtimes.
   **/
class Profiler
{
  friend Profiler& profiler();

private:
  Profiler();
  ~Profiler();

  typedef std::map< std::string, std::pair< bool, PerThreadValue<TimingData> > >
    KnownTimersMap;
  //! section name -> seconds
  typedef std::map< std::string, TimingData::DeltaType >
    Datamap;
  //! "Run idx" -> Datamap = section name -> seconds
  typedef std::vector< Datamap >
    DatamapVector;

  //! appends int to section name
  long stopTiming(const std::string section_name, const size_t i, const bool use_walltime);

  //! appends int to section name
  void startTiming(const std::string section_name, const size_t i);

  //! appends int to section name
  void resetTiming(const std::string section_name, const size_t i);

  //! appends int to section name
  long getTiming(const std::string section_name, const size_t i, const bool use_walltime ) const;
  //! get runtime of section in run run_number in milliseconds
  long getTimingIdx(const std::string section_name, const size_t run_number, const bool use_walltime) const;

public:
  //! set this to begin a named section
  void startTiming(const std::string section_name);

  //! stop named section's counter
  long stopTiming(const std::string section_name, const bool use_walltime = false);

  //! set elapsed time back to 0 for section_name
  void resetTiming(const std::string section_name);

  //! get runtime of section in current run in milliseconds
  long getTiming(const std::string section_name, const bool use_walltime = false) const;

  /** output to currently pre-defined (csv) file, does not output individual run results, but average over all recorded
   * results
     **/
  void outputAveraged(const int refineLevel,
                      const long numDofs,
                      const double scale_factor = 1.0) const;

  //! file-output the named sections only
  void outputTimings(const std::string filename) const;
  void outputTimings(std::ostream& out = std::cout) const;
  void outputTimingsAll(std::ostream& out = std::cout) const;

  /** call this with correct numRuns <b> before </b> starting any profiling
     *  if you're planning on doing more than one iteration of your code
     *  called once fromm ctor with numRuns=1
     **/
  void reset(const size_t numRuns);

  //! simple counter, usable to count how often a single piece of code is called
  void addCount(const size_t num);

  //! call this after one iteration of your code has finished. increments current run number and puts new timing data
  //! into the vector
  void nextRun();

  void setOutputdir(const std::string dir);

private:
  DatamapVector datamaps_;
  size_t current_run_number_;
  //! runtime tables etc go there
  std::string output_dir_;
  // debug counter, only outputted in debug mode
  std::map< size_t, size_t > counters_;

  KnownTimersMap known_timers_map_;
  const std::string csv_sep_;
  std::mutex mutex_;

  static Profiler& instance() {
    static Profiler pf;
    return pf;
  }

};

//! global profiler object
inline Profiler& profiler() {
  return Profiler::instance();
}

class ScopedTiming : public boost::noncopyable
{
protected:
  const std::string section_name_;

public:
  inline ScopedTiming(const std::string& section_name)
    : section_name_(section_name) {
    profiler().startTiming(section_name_);
  }

  inline ~ScopedTiming() {
    profiler().stopTiming(section_name_);
  }
};

struct OutputScopedTiming : public ScopedTiming {
  OutputScopedTiming(const std::string& section_name, std::ostream& out);

  ~OutputScopedTiming();
protected:
  std::ostream& out_;
};

} // namespace Common
} // namespace Stuff
} // namespace Dune

#define DSC_PROFILER Dune::Stuff::Common::profiler()

#if DUNE_STUFF_ENABLE_PROFILE_SCOPE
# define DUNE_STUFF_PROFILE_SCOPE(section_name) \
    Dune::Stuff::Common::ScopedTiming DUNE_UNUSED(timer)(section_name)
#else
# define DUNE_STUFF_PROFILE_SCOPE(section_name)
#endif

#endif // DUNE_STUFF_PROFILER_HH_INCLUDED
<commit_msg>[common.profiler] add DUNE_STUFF_DO_PROFILE<commit_after>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_PROFILER_HH_INCLUDED
#define DUNE_STUFF_PROFILER_HH_INCLUDED

#ifndef DUNE_STUFF_DO_PROFILE
# define DUNE_STUFF_DO_PROFILE 0
#endif
#if DUNE_STUFF_DO_PROFILE
# define DUNE_STUFF_ENABLE_PROFILE_SCOPE 1
#endif

#ifndef DUNE_STUFF_ENABLE_PROFILE_SCOPE
# define DUNE_STUFF_ENABLE_PROFILE_SCOPE 0
#endif

#include <string>
#include <map>
#include <vector>
#include <ctime>
#include <memory>
#include <iostream>
#include <mutex>

#include <boost/noncopyable.hpp>
#include <boost/timer/timer.hpp>

#include <dune/common/unused.hh>

#include <dune/stuff/common/parallel/threadmanager.hh>
#include <dune/stuff/common/parallel/threadstorage.hh>

namespace Dune {
namespace Stuff {
namespace Common {

class Profiler;

//! Stuff::Profiler global instance
Profiler& profiler();

//! wraps name, start- and end time for one timing section
struct TimingData
{
private:
  std::shared_ptr<boost::timer::cpu_timer> timer_;
public:
  std::string name;

  explicit TimingData(const std::string _name = "blank");

  void stop();

  typedef boost::timer::nanosecond_type TimeType;
  typedef std::array<TimeType, 4> DeltaType;

  /** \return time elapsed since object construction in milliseconds
   *  \note since typical resolutions for user+system time are 10-15ms the nanosecond results are scaled accordingly
   **/
  DeltaType delta() const;
};

//! a utility class to time a limited scope of code
class ScopedTiming;

/** \brief simple inline profiling class
   *  - User can set as many (even nested) named sections whose total (=system+user) time will be computed across all program
   * instances.\n
   *  - Provides csv-conform output of process-averaged runtimes.
   **/
class Profiler
{
  friend Profiler& profiler();

private:
  Profiler();
  ~Profiler();

  typedef std::map< std::string, std::pair< bool, PerThreadValue<TimingData> > >
    KnownTimersMap;
  //! section name -> seconds
  typedef std::map< std::string, TimingData::DeltaType >
    Datamap;
  //! "Run idx" -> Datamap = section name -> seconds
  typedef std::vector< Datamap >
    DatamapVector;

  //! appends int to section name
  long stopTiming(const std::string section_name, const size_t i, const bool use_walltime);

  //! appends int to section name
  void startTiming(const std::string section_name, const size_t i);

  //! appends int to section name
  void resetTiming(const std::string section_name, const size_t i);

  //! appends int to section name
  long getTiming(const std::string section_name, const size_t i, const bool use_walltime ) const;
  //! get runtime of section in run run_number in milliseconds
  long getTimingIdx(const std::string section_name, const size_t run_number, const bool use_walltime) const;

public:
  //! set this to begin a named section
  void startTiming(const std::string section_name);

  //! stop named section's counter
  long stopTiming(const std::string section_name, const bool use_walltime = false);

  //! set elapsed time back to 0 for section_name
  void resetTiming(const std::string section_name);

  //! get runtime of section in current run in milliseconds
  long getTiming(const std::string section_name, const bool use_walltime = false) const;

  /** output to currently pre-defined (csv) file, does not output individual run results, but average over all recorded
   * results
     **/
  void outputAveraged(const int refineLevel,
                      const long numDofs,
                      const double scale_factor = 1.0) const;

  //! file-output the named sections only
  void outputTimings(const std::string filename) const;
  void outputTimings(std::ostream& out = std::cout) const;
  void outputTimingsAll(std::ostream& out = std::cout) const;

  /** call this with correct numRuns <b> before </b> starting any profiling
     *  if you're planning on doing more than one iteration of your code
     *  called once fromm ctor with numRuns=1
     **/
  void reset(const size_t numRuns);

  //! simple counter, usable to count how often a single piece of code is called
  void addCount(const size_t num);

  //! call this after one iteration of your code has finished. increments current run number and puts new timing data
  //! into the vector
  void nextRun();

  void setOutputdir(const std::string dir);

private:
  DatamapVector datamaps_;
  size_t current_run_number_;
  //! runtime tables etc go there
  std::string output_dir_;
  // debug counter, only outputted in debug mode
  std::map< size_t, size_t > counters_;

  KnownTimersMap known_timers_map_;
  const std::string csv_sep_;
  std::mutex mutex_;

  static Profiler& instance() {
    static Profiler pf;
    return pf;
  }

};

//! global profiler object
inline Profiler& profiler() {
  return Profiler::instance();
}

class ScopedTiming : public boost::noncopyable
{
protected:
  const std::string section_name_;

public:
  inline ScopedTiming(const std::string& section_name)
    : section_name_(section_name) {
    profiler().startTiming(section_name_);
  }

  inline ~ScopedTiming() {
    profiler().stopTiming(section_name_);
  }
};

struct OutputScopedTiming : public ScopedTiming {
  OutputScopedTiming(const std::string& section_name, std::ostream& out);

  ~OutputScopedTiming();
protected:
  std::ostream& out_;
};

} // namespace Common
} // namespace Stuff
} // namespace Dune

#define DSC_PROFILER Dune::Stuff::Common::profiler()

#if DUNE_STUFF_ENABLE_PROFILE_SCOPE
# define DUNE_STUFF_PROFILE_SCOPE(section_name) \
    Dune::Stuff::Common::ScopedTiming DUNE_UNUSED(timer)(section_name)
#else
# define DUNE_STUFF_PROFILE_SCOPE(section_name)
#endif

#endif // DUNE_STUFF_PROFILER_HH_INCLUDED
<|endoftext|>


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

//
//  dl_livemap_service_io_manager_boost_impl.cpp
//  livemap_server
//
//  Created by Geon young Lim on 2017. 9. 5..
//
//

#include "dl_livemap_service_io_manager_boost_impl.hpp"
#include "command_binder.hpp"

namespace solarcode {
namespace livemap {
    dl_livemap_service_io_manager_boost_impl::dl_livemap_service_io_manager_boost_impl(std::weak_ptr<session_base> session, client_node_pool& node_pool)
    :solarcode::livemap::session_io_manager_base(session),
    _mutex_for_buffer(),
    _cv_for_buffer(),
    _io_service(get_shared_io_service()),
    _node_pool(node_pool),
    _buffer(nullptr),
    _buffer_size(0)
    {

    }

    boost::asio::strand
    dl_livemap_service_io_manager_boost_impl::_strand_for_node_pool
    = boost::asio::strand(get_shared_io_service());

    void dl_livemap_service_io_manager_boost_impl::session_read_after_buffer(char *const buffer, const std::size_t buffer_length)
    {

        auto unsafe_service = [this, buffer, buffer_length]() {
            std::unique_lock<std::mutex> lock_for_buffer(_mutex_for_buffer);

            _buffer_size = command_bind(get_session_owner(),_node_pool, buffer, buffer_length, &_buffer);

            delete [] buffer;
            //_cv_for_buffer.notify_one();

        };

        auto safe_service = _strand_for_node_pool.wrap(unsafe_service);
        _io_service.post(safe_service);

    }

    std::size_t dl_livemap_service_io_manager_boost_impl::session_write_before_buffer(char **buffer)
    {
        std::unique_lock<std::mutex> lock_for_buffer(_mutex_for_buffer);

        *buffer = _buffer;

        _buffer = nullptr;
        std::size_t size_to_return = _buffer_size;
        _buffer_size = 0;

        return size_to_return;
    }
}

}
<commit_msg>remove unnecessary comment.<commit_after>// Copyright 2017 GeunYoung Lim <interruping4dev@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//
//  dl_livemap_service_io_manager_boost_impl.cpp
//  livemap_server
//
//  Created by Geon young Lim on 2017. 9. 5..
//
//

#include "dl_livemap_service_io_manager_boost_impl.hpp"
#include "command_binder.hpp"

namespace solarcode {
namespace livemap {
    dl_livemap_service_io_manager_boost_impl::dl_livemap_service_io_manager_boost_impl(std::weak_ptr<session_base> session, client_node_pool& node_pool)
    :solarcode::livemap::session_io_manager_base(session),
    _mutex_for_buffer(),
    _cv_for_buffer(),
    _io_service(get_shared_io_service()),
    _node_pool(node_pool),
    _buffer(nullptr),
    _buffer_size(0)
    {

    }

    boost::asio::strand
    dl_livemap_service_io_manager_boost_impl::_strand_for_node_pool
    = boost::asio::strand(get_shared_io_service());

    void dl_livemap_service_io_manager_boost_impl::session_read_after_buffer(char *const buffer, const std::size_t buffer_length)
    {
        auto unsafe_service = [this, buffer, buffer_length]() {
            std::unique_lock<std::mutex> lock_for_buffer(_mutex_for_buffer);

            _buffer_size = command_bind(get_session_owner(),_node_pool, buffer, buffer_length, &_buffer);

            delete [] buffer;
        };

        auto safe_service = _strand_for_node_pool.wrap(unsafe_service);
        _io_service.post(safe_service);
    }

    std::size_t dl_livemap_service_io_manager_boost_impl::session_write_before_buffer(char **buffer)
    {
        std::unique_lock<std::mutex> lock_for_buffer(_mutex_for_buffer);

        *buffer = _buffer;

        _buffer = nullptr;
        std::size_t size_to_return = _buffer_size;
        _buffer_size = 0;

        return size_to_return;
    }
}

}
<|endoftext|>