<commit_before>/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "kernel/instantiate.h"
#include "kernel/inductive/inductive.h"
#include "library/user_recursors.h"
#include "library/blast/revert_action.h"
#include "library/blast/blast.h"

namespace lean {
namespace blast {
optional<name> is_recursor_action_target(hypothesis_idx hidx) {
    state & s = curr_state();
    hypothesis const * h = s.get_hypothesis_decl(hidx);
    lean_assert(h);
    expr const & type = h->get_type();
    if (!is_app(type) && !is_constant(type))
        return optional<name>();
    if (is_relation(type))
        return optional<name>(); // we don't apply recursors to equivalence relations: =, ~, <->, etc.
    if (!h->is_assumption())
        return optional<name>(); // we only consider assumptions
    // TODO(Leo): more restrictions?
    // TODO(Leo): consider user-provided hints
    expr const & I    = get_app_fn(type);
    if (!is_constant(I))
        return optional<name>();
    if (inductive::is_inductive_decl(env(), const_name(I)))
        return optional<name>(name(inductive::get_elim_name(const_name(I)))); // it is builtin recursive datatype
    list<name> Rs = get_recursors_for(env(), const_name(I));
    if (!Rs)
        return optional<name>();
    else
        return optional<name>(head(Rs)); // type has user-defined recursors
}

unsigned get_num_minor_premises(name const & R) {
    return get_recursor_info(env(), R).get_num_minors();
}

bool is_recursive_recursor(name const & R) {
    return get_recursor_info(env(), R).is_recursive();
}

struct recursor_proof_step_cell : public proof_step_cell {
    bool       m_dep;
    branch     m_branch;      // branch for backtracking
    expr       m_proof;       // recursor-application (the position where the goal-proofs are marked by the local constants).
    list<expr> m_goals;       // type of each subgoal/branch encoded as a local constant
    list<expr> m_goal_proofs; // proofs generated so far

    recursor_proof_step_cell(bool dep, branch const & b, expr const & pr, list<expr> const & goals, list<expr> const & goal_proofs):
        m_dep(dep), m_branch(b), m_proof(pr), m_goals(goals), m_goal_proofs(goal_proofs) {
    }

    virtual ~recursor_proof_step_cell() {}

    virtual action_result resolve(expr const & pr) const {
        state & s = curr_state();
        s.set_branch(m_branch);
        if (!m_dep) {
            // It is not a dependent elimination, so if pr did not use new hypothesis,
            // we don't need to investigate other branches.
            // This is also a form of non-chronological backtracking.
            expr const & goal    = head(m_goals);
            unsigned arity       = get_arity(mlocal_type(goal));
            expr it              = pr;
            bool skip            = true;
            for (unsigned i = 0; i < arity; i++) {
                if (!is_lambda(it)) {
                    skip = false;
                    break;
                }
                it = binding_body(it);
                if (!closed(it)) {
                    skip = false;
                    break;
                }
            }
            if (skip) {
                lean_assert(closed(it));
                return action_result::solved(it);
            }
        }
        list<expr> new_goals = tail(m_goals);
        list<expr> new_prs   = cons(pr, m_goal_proofs);
        if (empty(new_goals)) {
            buffer<expr> proof_args;
            buffer<expr> gs;
            to_buffer(m_goals, gs);
            expr const & rec = get_app_args(m_proof, proof_args);
            // update proof_args that are goals with their proofs
            unsigned i = proof_args.size();
            while (i > 0) {
                --i;
                if (!gs.empty() && proof_args[i] == gs.back()) {
                    lean_assert(new_prs);
                    proof_args[i] = head(new_prs);
                    new_prs       = tail(new_prs);
                }
            }
            return action_result::solved(mk_app(rec, proof_args));
        } else {
            s.pop_proof_step();
            s.push_proof_step(new recursor_proof_step_cell(m_dep, m_branch, m_proof, new_goals, new_prs));
            s.set_target(mlocal_type(head(new_goals)));
            return action_result::new_branch();
        }
    }
};

action_result recursor_action(hypothesis_idx hidx, name const & R) {
    state & s = curr_state();
    hypothesis const * h = s.get_hypothesis_decl(hidx);
    lean_assert(h);
    expr const & type = h->get_type();
    lean_assert(is_constant(get_app_fn(type)));

    recursor_info rec_info = get_recursor_info(env(), R);

    if (!rec_info.has_dep_elim() && s.target_depends_on(hidx)) {
        // recursor does does not support dependent elimination, but conclusion
        // depends on major premise
        return action_result::failed();
    }

    buffer<expr> type_args;
    get_app_args(type, type_args);
    buffer<optional<expr>> params;
    for (optional<unsigned> const & pos : rec_info.get_params_pos()) {
        if (!pos) {
            params.push_back(none_expr());
        } else if (*pos >= type_args.size()) {
            return action_result::failed(); // major premise type is ill-formed
        } else {
            params.push_back(some_expr(type_args[*pos]));
        }
    }

    buffer<expr> indices;
    list<unsigned> const & idx_pos = rec_info.get_indices_pos();
    for (unsigned pos : idx_pos) {
        if (pos >= type_args.size()) {
            return action_result::failed(); // major premise type is ill-formed");
        }
        expr const & idx = type_args[pos];
        if (!is_href(idx)) {
            return action_result::failed(); // argument of major premise type is not a href
        }
        for (unsigned i = 0; i < type_args.size(); i++) {
            if (i != pos && is_local(type_args[i]) && mlocal_name(type_args[i]) == mlocal_name(idx)) {
                return action_result::failed(); // argument of major premise is an index, but it occurs more than once
            }
            if (i > pos && // occurs after idx
                std::find(idx_pos.begin(), idx_pos.end(), i) != idx_pos.end() && // it is also an index
                is_href(type_args[i]) && // if it is not an index, it will fail anyway.
                s.hidx_depends_on(href_index(idx), href_index(type_args[i]))) {
                // argument of major premise type is an index, but its type depends on another index
                return action_result::failed();
            }
        }
        indices.push_back(idx);
    }

    scope_curr_state save_state;
    hypothesis_idx_buffer_set to_revert;
    s.collect_direct_forward_deps(hidx, to_revert);
    for (auto i : indices)
        s.collect_direct_forward_deps(href_index(i), to_revert);
    revert_action(to_revert);

    expr target       = s.get_target();
    auto target_level = get_type_context().get_level_core(target);
    if (!target_level) return action_result::failed(); // failed to extract universe level of target

    buffer<level> rec_lvls;
    expr const & I = get_app_fn(type);
    buffer<level> I_lvls;
    to_buffer(const_levels(I), I_lvls);
    bool found_target_lvl = false;
    for (unsigned idx : rec_info.get_universe_pos()) {
        if (idx == recursor_info::get_motive_univ_idx()) {
            rec_lvls.push_back(*target_level);
            found_target_lvl = true;
        } else {
            if (idx >= I_lvls.size())
                return action_result::failed(); // ill-formed recursor
            rec_lvls.push_back(I_lvls[idx]);
        }
    }

    if (!found_target_lvl && !is_zero(*target_level)) {
        // recursor can only eliminate into Prop
        return action_result::failed();
    }
    expr rec    = mk_constant(rec_info.get_name(), to_list(rec_lvls));

    for (optional<expr> const & p : params) {
        if (p) {
            rec = mk_app(rec, *p);
        } else {
            // try type class resolution to synthesize argument
            expr rec_type = relaxed_whnf(infer_type(rec));
            if (!is_pi(rec_type))
                return action_result::failed(); // ill-formed recursor
            expr arg_type = binding_domain(rec_type);
            if (auto inst = mk_class_instance(arg_type)) {
                rec = mk_app(rec, *inst);
            } else {
                return action_result::failed(); // failed to generate instance
            }
        }
    }

    expr motive = target;
    if (rec_info.has_dep_elim())
        motive  = s.mk_lambda(h->get_self(), motive);
    motive = s.mk_lambda(indices, motive);
    rec      = mk_app(rec, motive);

    expr rec_type          = relaxed_whnf(infer_type(rec));
    unsigned curr_pos      = params.size() + 1 /* motive */;
    unsigned first_idx_pos = rec_info.get_first_index_pos();
    bool consumed_major    = false;
    buffer<expr> new_goals;

    while (is_pi(rec_type) && curr_pos < rec_info.get_num_args()) {
        if (first_idx_pos == curr_pos) {
            for (expr const & idx : indices) {
                rec      = mk_app(rec, idx);
                rec_type = relaxed_whnf(instantiate(binding_body(rec_type), idx));
                if (!is_pi(rec_type))
                    return action_result::failed(); // ill-formed type
                curr_pos++;
            }
            rec      = mk_app(rec, h->get_self());
            rec_type = relaxed_whnf(instantiate(binding_body(rec_type), h->get_self()));
            consumed_major = true;
            curr_pos++;
        } else {
            expr new_type  = binding_domain(rec_type);
            expr rec_arg;
            if (binding_info(rec_type).is_inst_implicit()) {
                auto inst = mk_class_instance(new_type);
                if (!inst) return action_result::failed(); // type class resolution failed
                rec_arg   = *inst;
            } else {
                rec_arg = mk_fresh_local(new_type); // placeholder
                new_goals.push_back(rec_arg);
            }
            rec       = mk_app(rec, rec_arg);
            rec_type  = relaxed_whnf(instantiate(binding_body(rec_type), rec_arg));
            curr_pos++;
        }
    }

    if (curr_pos != rec_info.get_num_args() || !consumed_major)
        return action_result::failed(); // ill-formed recursor

    save_state.commit();

    if (new_goals.empty())
        return action_result::solved(rec);
    s.del_hypothesis(hidx);
    s.push_proof_step(new recursor_proof_step_cell(rec_info.has_dep_elim(), s.get_branch(), rec, to_list(new_goals), list<expr>()));
    s.set_target(mlocal_type(new_goals[0]));
    return action_result::new_branch();
}

action_result recursor_action(hypothesis_idx hidx) {
    state & s = curr_state();
    hypothesis const * h = s.get_hypothesis_decl(hidx);
    lean_assert(h);
    expr const & type = h->get_type();
    expr const & I    = get_app_fn(type);
    if (!is_constant(I))
        return action_result::failed();
    list<name> Rs = get_recursors_for(env(), const_name(I));
    for (auto R : Rs) {
        auto r = recursor_action(hidx, R);
        if (!failed(r))
            return r;
    }
    return action_result::failed();
}
}}
<commit_msg>feat(library/blast/recursor_action): ignore type class instances in the recursor action<commit_after>/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "kernel/instantiate.h"
#include "kernel/inductive/inductive.h"
#include "library/user_recursors.h"
#include "library/blast/revert_action.h"
#include "library/blast/blast.h"

namespace lean {
namespace blast {
optional<name> is_recursor_action_target(hypothesis_idx hidx) {
    state & s = curr_state();
    hypothesis const * h = s.get_hypothesis_decl(hidx);
    lean_assert(h);
    expr const & type = h->get_type();
    if (!is_app(type) && !is_constant(type))
        return optional<name>();
    if (is_relation(type))
        return optional<name>(); // we don't apply recursors to equivalence relations: =, ~, <->, etc.
    if (!h->is_assumption())
        return optional<name>(); // we only consider assumptions
    if (get_type_context().is_class(type)) {
        // we don't eliminate type classes instances
        // TODO(Leo): we may revise that in the future... some type classes instances may be worth eliminating (e.g., decidable).
        return optional<name>();
    }
    // TODO(Leo): more restrictions?
    // TODO(Leo): consider user-provided hints
    expr const & I    = get_app_fn(type);
    if (!is_constant(I))
        return optional<name>();
    if (inductive::is_inductive_decl(env(), const_name(I)))
        return optional<name>(name(inductive::get_elim_name(const_name(I)))); // it is builtin recursive datatype
    list<name> Rs = get_recursors_for(env(), const_name(I));
    if (!Rs)
        return optional<name>();
    else
        return optional<name>(head(Rs)); // type has user-defined recursors
}

unsigned get_num_minor_premises(name const & R) {
    return get_recursor_info(env(), R).get_num_minors();
}

bool is_recursive_recursor(name const & R) {
    return get_recursor_info(env(), R).is_recursive();
}

struct recursor_proof_step_cell : public proof_step_cell {
    bool       m_dep;
    branch     m_branch;      // branch for backtracking
    expr       m_proof;       // recursor-application (the position where the goal-proofs are marked by the local constants).
    list<expr> m_goals;       // type of each subgoal/branch encoded as a local constant
    list<expr> m_goal_proofs; // proofs generated so far

    recursor_proof_step_cell(bool dep, branch const & b, expr const & pr, list<expr> const & goals, list<expr> const & goal_proofs):
        m_dep(dep), m_branch(b), m_proof(pr), m_goals(goals), m_goal_proofs(goal_proofs) {
    }

    virtual ~recursor_proof_step_cell() {}

    virtual action_result resolve(expr const & pr) const {
        state & s = curr_state();
        s.set_branch(m_branch);
        if (!m_dep) {
            // It is not a dependent elimination, so if pr did not use new hypothesis,
            // we don't need to investigate other branches.
            // This is also a form of non-chronological backtracking.
            expr const & goal    = head(m_goals);
            unsigned arity       = get_arity(mlocal_type(goal));
            expr it              = pr;
            bool skip            = true;
            for (unsigned i = 0; i < arity; i++) {
                if (!is_lambda(it)) {
                    skip = false;
                    break;
                }
                it = binding_body(it);
                if (!closed(it)) {
                    skip = false;
                    break;
                }
            }
            if (skip) {
                lean_assert(closed(it));
                return action_result::solved(it);
            }
        }
        list<expr> new_goals = tail(m_goals);
        list<expr> new_prs   = cons(pr, m_goal_proofs);
        if (empty(new_goals)) {
            buffer<expr> proof_args;
            buffer<expr> gs;
            to_buffer(m_goals, gs);
            expr const & rec = get_app_args(m_proof, proof_args);
            // update proof_args that are goals with their proofs
            unsigned i = proof_args.size();
            while (i > 0) {
                --i;
                if (!gs.empty() && proof_args[i] == gs.back()) {
                    lean_assert(new_prs);
                    proof_args[i] = head(new_prs);
                    new_prs       = tail(new_prs);
                }
            }
            return action_result::solved(mk_app(rec, proof_args));
        } else {
            s.pop_proof_step();
            s.push_proof_step(new recursor_proof_step_cell(m_dep, m_branch, m_proof, new_goals, new_prs));
            s.set_target(mlocal_type(head(new_goals)));
            return action_result::new_branch();
        }
    }
};

action_result recursor_action(hypothesis_idx hidx, name const & R) {
    state & s = curr_state();
    hypothesis const * h = s.get_hypothesis_decl(hidx);
    lean_assert(h);
    expr const & type = h->get_type();
    lean_assert(is_constant(get_app_fn(type)));

    recursor_info rec_info = get_recursor_info(env(), R);

    if (!rec_info.has_dep_elim() && s.target_depends_on(hidx)) {
        // recursor does does not support dependent elimination, but conclusion
        // depends on major premise
        return action_result::failed();
    }

    buffer<expr> type_args;
    get_app_args(type, type_args);
    buffer<optional<expr>> params;
    for (optional<unsigned> const & pos : rec_info.get_params_pos()) {
        if (!pos) {
            params.push_back(none_expr());
        } else if (*pos >= type_args.size()) {
            return action_result::failed(); // major premise type is ill-formed
        } else {
            params.push_back(some_expr(type_args[*pos]));
        }
    }

    buffer<expr> indices;
    list<unsigned> const & idx_pos = rec_info.get_indices_pos();
    for (unsigned pos : idx_pos) {
        if (pos >= type_args.size()) {
            return action_result::failed(); // major premise type is ill-formed");
        }
        expr const & idx = type_args[pos];
        if (!is_href(idx)) {
            return action_result::failed(); // argument of major premise type is not a href
        }
        for (unsigned i = 0; i < type_args.size(); i++) {
            if (i != pos && is_local(type_args[i]) && mlocal_name(type_args[i]) == mlocal_name(idx)) {
                return action_result::failed(); // argument of major premise is an index, but it occurs more than once
            }
            if (i > pos && // occurs after idx
                std::find(idx_pos.begin(), idx_pos.end(), i) != idx_pos.end() && // it is also an index
                is_href(type_args[i]) && // if it is not an index, it will fail anyway.
                s.hidx_depends_on(href_index(idx), href_index(type_args[i]))) {
                // argument of major premise type is an index, but its type depends on another index
                return action_result::failed();
            }
        }
        indices.push_back(idx);
    }

    scope_curr_state save_state;
    hypothesis_idx_buffer_set to_revert;
    s.collect_direct_forward_deps(hidx, to_revert);
    for (auto i : indices)
        s.collect_direct_forward_deps(href_index(i), to_revert);
    revert_action(to_revert);

    expr target       = s.get_target();
    auto target_level = get_type_context().get_level_core(target);
    if (!target_level) return action_result::failed(); // failed to extract universe level of target

    buffer<level> rec_lvls;
    expr const & I = get_app_fn(type);
    buffer<level> I_lvls;
    to_buffer(const_levels(I), I_lvls);
    bool found_target_lvl = false;
    for (unsigned idx : rec_info.get_universe_pos()) {
        if (idx == recursor_info::get_motive_univ_idx()) {
            rec_lvls.push_back(*target_level);
            found_target_lvl = true;
        } else {
            if (idx >= I_lvls.size())
                return action_result::failed(); // ill-formed recursor
            rec_lvls.push_back(I_lvls[idx]);
        }
    }

    if (!found_target_lvl && !is_zero(*target_level)) {
        // recursor can only eliminate into Prop
        return action_result::failed();
    }
    expr rec    = mk_constant(rec_info.get_name(), to_list(rec_lvls));

    for (optional<expr> const & p : params) {
        if (p) {
            rec = mk_app(rec, *p);
        } else {
            // try type class resolution to synthesize argument
            expr rec_type = relaxed_whnf(infer_type(rec));
            if (!is_pi(rec_type))
                return action_result::failed(); // ill-formed recursor
            expr arg_type = binding_domain(rec_type);
            if (auto inst = mk_class_instance(arg_type)) {
                rec = mk_app(rec, *inst);
            } else {
                return action_result::failed(); // failed to generate instance
            }
        }
    }

    expr motive = target;
    if (rec_info.has_dep_elim())
        motive  = s.mk_lambda(h->get_self(), motive);
    motive = s.mk_lambda(indices, motive);
    rec      = mk_app(rec, motive);

    expr rec_type          = relaxed_whnf(infer_type(rec));
    unsigned curr_pos      = params.size() + 1 /* motive */;
    unsigned first_idx_pos = rec_info.get_first_index_pos();
    bool consumed_major    = false;
    buffer<expr> new_goals;

    while (is_pi(rec_type) && curr_pos < rec_info.get_num_args()) {
        if (first_idx_pos == curr_pos) {
            for (expr const & idx : indices) {
                rec      = mk_app(rec, idx);
                rec_type = relaxed_whnf(instantiate(binding_body(rec_type), idx));
                if (!is_pi(rec_type))
                    return action_result::failed(); // ill-formed type
                curr_pos++;
            }
            rec      = mk_app(rec, h->get_self());
            rec_type = relaxed_whnf(instantiate(binding_body(rec_type), h->get_self()));
            consumed_major = true;
            curr_pos++;
        } else {
            expr new_type  = binding_domain(rec_type);
            expr rec_arg;
            if (binding_info(rec_type).is_inst_implicit()) {
                auto inst = mk_class_instance(new_type);
                if (!inst) return action_result::failed(); // type class resolution failed
                rec_arg   = *inst;
            } else {
                rec_arg = mk_fresh_local(new_type); // placeholder
                new_goals.push_back(rec_arg);
            }
            rec       = mk_app(rec, rec_arg);
            rec_type  = relaxed_whnf(instantiate(binding_body(rec_type), rec_arg));
            curr_pos++;
        }
    }

    if (curr_pos != rec_info.get_num_args() || !consumed_major)
        return action_result::failed(); // ill-formed recursor

    save_state.commit();

    if (new_goals.empty())
        return action_result::solved(rec);
    s.del_hypothesis(hidx);
    s.push_proof_step(new recursor_proof_step_cell(rec_info.has_dep_elim(), s.get_branch(), rec, to_list(new_goals), list<expr>()));
    s.set_target(mlocal_type(new_goals[0]));
    return action_result::new_branch();
}

action_result recursor_action(hypothesis_idx hidx) {
    state & s = curr_state();
    hypothesis const * h = s.get_hypothesis_decl(hidx);
    lean_assert(h);
    expr const & type = h->get_type();
    expr const & I    = get_app_fn(type);
    if (!is_constant(I))
        return action_result::failed();
    list<name> Rs = get_recursors_for(env(), const_name(I));
    for (auto R : Rs) {
        auto r = recursor_action(hidx, R);
        if (!failed(r))
            return r;
    }
    return action_result::failed();
}
}}
<|endoftext|>


<commit_before>/*
 * FastMETISParser.cpp
 *
 *  Created on: 04.10.2013
 *      Author: cls
 */

#include "FastMETISParser.h"

#include <fstream>

namespace NetworKit {

FastMETISParser::FastMETISParser() {
	// TODO Auto-generated constructor stub

}

FastMETISParser::~FastMETISParser() {
	// TODO Auto-generated destructor stub
}

static inline node fast_string_to_node(std::string::iterator it, const std::string::iterator& end) {
	node val = *it - '0';	// works on ASCII code points
	++it;
	while (it != end) {
		val *= 10;
		val += *it  - '0';
		++it;
	}
	return val;
}

static inline std::tuple<count, count, int> parseHeader(const std::string& header) {
	count n;
	count m;
	int flag;

	std::vector<std::string> parts = Aux::StringTools::split(header);
	n = std::stoi(parts[0]);
	m = std::stoi(parts[1]);
	flag = std::stoi(parts[2]);

	return std::make_tuple(n, m, flag);
}

NetworKit::Graph FastMETISParser::parse(const std::string& path) {
	std::ifstream stream(path);
	std::string line;
	std::getline(stream, line); // get header
	count n;
	count m;
	int flag; // weight flag
	std::tie(n, m, flag) = parseHeader(line);
	Graph G(n);
	node u = 0;
	while(std::getline(stream, line)) {
		++u;
		if(line.empty()){
			continue;
		}
		auto it1 = line.begin();
		auto end = line.end();
		auto it2 = std::find(it1, end, ' ');
		if (line.back() == ' ') { // if line ends with one white space, do this trick...
			--end;
		}
		while(true) {
			node v = fast_string_to_node(it1, it2);
			if (u < v) {
				G.addEdge(u, v);
			}
			if(it2 == end) {
				break;
			}
			++it2;
			it1 = it2;
			it2 = std::find(it1, end, ' ');
		}
	}
	return G;
}

} /* namespace NetworKit */
<commit_msg>minor edits on FastMETISParser<commit_after>/*
 * FastMETISParser.cpp
 *
 *  Created on: 04.10.2013
 *      Author: cls
 */

#include "FastMETISParser.h"

#include <fstream>

namespace NetworKit {

FastMETISParser::FastMETISParser() {
	// TODO Auto-generated constructor stub

}

FastMETISParser::~FastMETISParser() {
	// TODO Auto-generated destructor stub
}

static inline node fast_string_to_node(std::string::iterator it, const std::string::iterator& end) {
	node val = *it - '0';	// works on ASCII code points
	++it;
	while (it != end) {
		val *= 10;
		val += *it  - '0';
		++it;
	}
	return val;
}

static inline std::tuple<count, count, int> parseHeader(const std::string& header) {
	count n;
	count m;
	int flag;

	std::vector<std::string> parts = Aux::StringTools::split(header);
	n = std::stoi(parts[0]);
	m = std::stoi(parts[1]);
	if (parts.size > 2) {
		flag = std::stoi(parts[2]);
	} else {
		flag = 0;
	}

	return std::make_tuple(n, m, flag);
}

NetworKit::Graph FastMETISParser::parse(const std::string& path) {
	std::ifstream stream(path);
	std::string line;
	std::getline(stream, line); // get header
	count n;
	count m;
	int flag; // weight flag
	std::tie(n, m, flag) = parseHeader(line);
	Graph G(n);
	node u = 0;

	if (flag == 0) {
		while (std::getline(stream, line)) {
			++u;
			if (line.empty()) {
				continue;
			}
			auto it1 = line.begin();
			auto end = line.end();
			auto it2 = std::find(it1, end, ' ');
			if (line.back() == ' ') { // if line ends with one white space, do this trick...
				--end;
			}
			while (true) {
				node v = fast_string_to_node(it1, it2);
				if (u < v) {
					G.addEdge(u, v);
				}
				if (it2 == end) {
					break;
				}
				++it2;
				it1 = it2;
				it2 = std::find(it1, end, ' ');
			}
		}
	} else {
		ERROR("parsing graphs with weight flag " << flag << " not yet supported");
		exit(1);
	}

	return G;
}

} /* namespace NetworKit */
<|endoftext|>


<commit_before>/* Copyright 2016 Google Inc. All Rights Reserved.

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.
==============================================================================*/

#include "src/report_aggregator_impl.h"
#include "src/signature.h"

#include "google/protobuf/stubs/logging.h"

using std::string;
using ::google::api::MetricDescriptor;
using ::google::api::servicecontrol::v1::Operation;
using ::google::api::servicecontrol::v1::ReportRequest;
using ::google::api::servicecontrol::v1::ReportResponse;
using ::google::protobuf::util::Status;
using ::google::protobuf::util::error::Code;

namespace google {
namespace service_control_client {
namespace {

// A report can carry many operations, merge multiple report requests
// into one report request until its number of operations reach this limit.
const int kMaxOperationsToSend = 1000;

// Returns whether the given report request has high value operations.
bool HasHighImportantOperation(const ReportRequest& request) {
  for (const auto& operation : request.operations()) {
    if (operation.importance() != Operation::LOW) {
      return true;
    }
  }
  return false;
}

}  // namespace

ReportAggregatorImpl::ReportAggregatorImpl(
    const string& service_name, const std::string& service_config_id,
    const ReportAggregationOptions& options,
    std::shared_ptr<MetricKindMap> metric_kinds)
    : service_name_(service_name),
      service_config_id_(service_config_id),
      options_(options),
      metric_kinds_(metric_kinds) {
  if (options.num_entries > 0) {
    cache_.reset(
        new ReportCache(options.num_entries,
                        std::bind(&ReportAggregatorImpl::OnCacheEntryDelete,
                                  this, std::placeholders::_1)));
    cache_->SetAgeBasedEviction(options.flush_interval_ms / 1000.0);
  }
}

ReportAggregatorImpl::~ReportAggregatorImpl() {
  // FlushAll() is a blocking call to remove all cache items.
  // For each removed item, it will call flush_callback().
  // At the destructor, it is better not to call the callback.
  SetFlushCallback(NULL);
  FlushAll();
}

// Set the flush callback function.
void ReportAggregatorImpl::SetFlushCallback(FlushCallback callback) {
  InternalSetFlushCallback(callback);
}

// Add a report request to cache
Status ReportAggregatorImpl::Report(
    const ::google::api::servicecontrol::v1::ReportRequest& request) {
  if (request.service_name() != service_name_) {
    return Status(Code::INVALID_ARGUMENT,
                  (string("Invalid service name: ") + request.service_name() +
                   string(" Expecting: ") + service_name_));
  }
  if (HasHighImportantOperation(request) || !cache_) {
    // By returning NO_FOUND, caller will send request to server.
    return Status(Code::NOT_FOUND, "");
  }

  ReportCacheRemovedItemsHandler::StackBuffer stack_buffer(this);
  MutexLock lock(cache_mutex_);
  ReportCacheRemovedItemsHandler::StackBuffer::Swapper swapper(this,
                                                               &stack_buffer);

  // Starts to cache and aggregate low important operations.
  for (const auto& operation : request.operations()) {
    string signature = GenerateReportOperationSignature(operation);

    ReportCache::ScopedLookup lookup(cache_.get(), signature);
    if (lookup.Found()) {
      lookup.value()->MergeOperation(operation);
    } else {
      OperationAggregator* iop =
          new OperationAggregator(operation, metric_kinds_.get());
      cache_->Insert(signature, iop, 1);
    }
  }
  return Status::OK;
}

void ReportAggregatorImpl::OnCacheEntryDelete(OperationAggregator* iop) {
  // iop or cache is under projected.  This function is only called when
  // cache::Insert() or cache::Removed() is called and these operations
  // are already protected by cache_mutex.
  ReportRequest request;
  request.set_service_name(service_name_);
  request.set_service_config_id(service_config_id_);
  // TODO(qiwzhang): Remove this copy
  *(request.add_operations()) = iop->ToOperationProto();
  delete iop;

  AddRemovedItem(request);
}

bool ReportAggregatorImpl::MergeItem(const ReportRequest& new_item,
                                     ReportRequest* old_item) {
  if (old_item->service_name() != new_item.service_name() ||
      old_item->operations().size() + new_item.operations().size() >
          kMaxOperationsToSend) {
    return false;
  }
  old_item->MergeFrom(new_item);
  return true;
}

// When the next Flush() should be called.
// Return in ms from now, or -1 for never
int ReportAggregatorImpl::GetNextFlushInterval() {
  if (!cache_) return -1;
  return options_.flush_interval_ms;
}

// Flush aggregated requests whom are longer than flush_interval.
// Called at time specified by GetNextFlushInterval().
Status ReportAggregatorImpl::Flush() {
  ReportCacheRemovedItemsHandler::StackBuffer stack_buffer(this);
  MutexLock lock(cache_mutex_);
  ReportCacheRemovedItemsHandler::StackBuffer::Swapper swapper(this,
                                                               &stack_buffer);
  if (cache_) {
    cache_->RemoveExpiredEntries();
  }
  return Status::OK;
}

// Flush out aggregated report requests, clear all cache items.
// Usually called at destructor.
Status ReportAggregatorImpl::FlushAll() {
  ReportCacheRemovedItemsHandler::StackBuffer stack_buffer(this);
  MutexLock lock(cache_mutex_);
  ReportCacheRemovedItemsHandler::StackBuffer::Swapper swapper(this,
                                                               &stack_buffer);
  GOOGLE_LOG(INFO) << "Remove all entries of report aggregator.";
  if (cache_) {
    cache_->RemoveAll();
  }
  return Status::OK;
}

std::unique_ptr<ReportAggregator> CreateReportAggregator(
    const std::string& service_name, const std::string& service_config_id,
    const ReportAggregationOptions& options,
    std::shared_ptr<MetricKindMap> metric_kind) {
  return std::unique_ptr<ReportAggregator>(new ReportAggregatorImpl(
      service_name, service_config_id, options, metric_kind));
}

}  // namespace service_control_client
}  // namespace google
<commit_msg>Reduce kMaxOperationsToSend from to 100 so its size is within 1MB limit<commit_after>/* Copyright 2016 Google Inc. All Rights Reserved.

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.
==============================================================================*/

#include "src/report_aggregator_impl.h"
#include "src/signature.h"

#include "google/protobuf/stubs/logging.h"

using std::string;
using ::google::api::MetricDescriptor;
using ::google::api::servicecontrol::v1::Operation;
using ::google::api::servicecontrol::v1::ReportRequest;
using ::google::api::servicecontrol::v1::ReportResponse;
using ::google::protobuf::util::Status;
using ::google::protobuf::util::error::Code;

namespace google {
namespace service_control_client {
namespace {

// A report can carry many operations, merge multiple report requests
// into one report request until its number of operations reach this limit.
// Each report is about 4KB now. Maximum allowed size from server is 1MB.
const int kMaxOperationsToSend = 100;

// Returns whether the given report request has high value operations.
bool HasHighImportantOperation(const ReportRequest& request) {
  for (const auto& operation : request.operations()) {
    if (operation.importance() != Operation::LOW) {
      return true;
    }
  }
  return false;
}

}  // namespace

ReportAggregatorImpl::ReportAggregatorImpl(
    const string& service_name, const std::string& service_config_id,
    const ReportAggregationOptions& options,
    std::shared_ptr<MetricKindMap> metric_kinds)
    : service_name_(service_name),
      service_config_id_(service_config_id),
      options_(options),
      metric_kinds_(metric_kinds) {
  if (options.num_entries > 0) {
    cache_.reset(
        new ReportCache(options.num_entries,
                        std::bind(&ReportAggregatorImpl::OnCacheEntryDelete,
                                  this, std::placeholders::_1)));
    cache_->SetAgeBasedEviction(options.flush_interval_ms / 1000.0);
  }
}

ReportAggregatorImpl::~ReportAggregatorImpl() {
  // FlushAll() is a blocking call to remove all cache items.
  // For each removed item, it will call flush_callback().
  // At the destructor, it is better not to call the callback.
  SetFlushCallback(NULL);
  FlushAll();
}

// Set the flush callback function.
void ReportAggregatorImpl::SetFlushCallback(FlushCallback callback) {
  InternalSetFlushCallback(callback);
}

// Add a report request to cache
Status ReportAggregatorImpl::Report(
    const ::google::api::servicecontrol::v1::ReportRequest& request) {
  if (request.service_name() != service_name_) {
    return Status(Code::INVALID_ARGUMENT,
                  (string("Invalid service name: ") + request.service_name() +
                   string(" Expecting: ") + service_name_));
  }
  if (HasHighImportantOperation(request) || !cache_) {
    // By returning NO_FOUND, caller will send request to server.
    return Status(Code::NOT_FOUND, "");
  }

  ReportCacheRemovedItemsHandler::StackBuffer stack_buffer(this);
  MutexLock lock(cache_mutex_);
  ReportCacheRemovedItemsHandler::StackBuffer::Swapper swapper(this,
                                                               &stack_buffer);

  // Starts to cache and aggregate low important operations.
  for (const auto& operation : request.operations()) {
    string signature = GenerateReportOperationSignature(operation);

    ReportCache::ScopedLookup lookup(cache_.get(), signature);
    if (lookup.Found()) {
      lookup.value()->MergeOperation(operation);
    } else {
      OperationAggregator* iop =
          new OperationAggregator(operation, metric_kinds_.get());
      cache_->Insert(signature, iop, 1);
    }
  }
  return Status::OK;
}

void ReportAggregatorImpl::OnCacheEntryDelete(OperationAggregator* iop) {
  // iop or cache is under projected.  This function is only called when
  // cache::Insert() or cache::Removed() is called and these operations
  // are already protected by cache_mutex.
  ReportRequest request;
  request.set_service_name(service_name_);
  request.set_service_config_id(service_config_id_);
  // TODO(qiwzhang): Remove this copy
  *(request.add_operations()) = iop->ToOperationProto();
  delete iop;

  AddRemovedItem(request);
}

bool ReportAggregatorImpl::MergeItem(const ReportRequest& new_item,
                                     ReportRequest* old_item) {
  if (old_item->service_name() != new_item.service_name() ||
      old_item->operations().size() + new_item.operations().size() >
          kMaxOperationsToSend) {
    return false;
  }
  old_item->MergeFrom(new_item);
  return true;
}

// When the next Flush() should be called.
// Return in ms from now, or -1 for never
int ReportAggregatorImpl::GetNextFlushInterval() {
  if (!cache_) return -1;
  return options_.flush_interval_ms;
}

// Flush aggregated requests whom are longer than flush_interval.
// Called at time specified by GetNextFlushInterval().
Status ReportAggregatorImpl::Flush() {
  ReportCacheRemovedItemsHandler::StackBuffer stack_buffer(this);
  MutexLock lock(cache_mutex_);
  ReportCacheRemovedItemsHandler::StackBuffer::Swapper swapper(this,
                                                               &stack_buffer);
  if (cache_) {
    cache_->RemoveExpiredEntries();
  }
  return Status::OK;
}

// Flush out aggregated report requests, clear all cache items.
// Usually called at destructor.
Status ReportAggregatorImpl::FlushAll() {
  ReportCacheRemovedItemsHandler::StackBuffer stack_buffer(this);
  MutexLock lock(cache_mutex_);
  ReportCacheRemovedItemsHandler::StackBuffer::Swapper swapper(this,
                                                               &stack_buffer);
  GOOGLE_LOG(INFO) << "Remove all entries of report aggregator.";
  if (cache_) {
    cache_->RemoveAll();
  }
  return Status::OK;
}

std::unique_ptr<ReportAggregator> CreateReportAggregator(
    const std::string& service_name, const std::string& service_config_id,
    const ReportAggregationOptions& options,
    std::shared_ptr<MetricKindMap> metric_kind) {
  return std::unique_ptr<ReportAggregator>(new ReportAggregatorImpl(
      service_name, service_config_id, options, metric_kind));
}

}  // namespace service_control_client
}  // namespace google
<|endoftext|>


<commit_before>/*
 * opencog/server/Agent.cc
 *
 * Copyright (C) 2008 by OpenCog Foundation
 * All Rights Reserved
 *
 * Written by Gustavo Gama <gama@vettalabs.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "Agent.h"

#include <opencog/server/CogServer.h>
#include <opencog/util/Config.h>

using namespace opencog;

Agent::Agent(CogServer& cs, const unsigned int f) : _cogserver(cs), _frequency(f)
{
    // an empty set of parameters and defaults (so that various
    // methods will still work even if none are set in this or a derived
    // class)
    static const std::string defaultConfig[] = {
        "", ""
    };
    setParameters(defaultConfig);

    stimulatedAtoms = new AtomStimHashMap();
    totalStimulus = 0;

    conn = _cogserver.getAtomSpace().atomSpaceAsync->removeAtomSignal(
            boost::bind(&Agent::atomRemoved, this, _1, _2));
}

Agent::~Agent()
{
    // give back funds
    _cogserver.getAtomSpace().getAttentionBank().setSTI(AttentionValueHolderPtr(this), 0);
    _cogserver.getAtomSpace().getAttentionBank().setLTI(AttentionValueHolderPtr(this), 0);

    resetUtilizedHandleSets();
    delete stimulatedAtoms;
    conn.disconnect();
}

void Agent::setParameters(const std::string* params)
{
    PARAMETERS = params;

    for (unsigned int i = 0; params[i] != ""; i += 2) {
        if (!config().has(params[i])) {
           config().set(params[i], params[i + 1]);
        }
    }
}

std::string Agent::to_string() const
{
    std::ostringstream oss;
    oss << classinfo().id;
    oss << " {\"";
    for (unsigned int i = 0; PARAMETERS[i] != ""; i += 2) {
        if (i != 0) oss << "\", \"";
        oss << PARAMETERS[i] << "\" => \"" << config()[PARAMETERS[i]];
    }
    oss << "\"}";
    return oss.str();
}

void Agent::atomRemoved(AtomSpaceImpl* a, Handle h)
{
    for (size_t i = 0; i < _utilizedHandleSets.size(); i++)
        _utilizedHandleSets[i].erase(h);
    removeAtomStimulus(h);
}

void Agent::resetUtilizedHandleSets()
{
    for (size_t i = 0; i < _utilizedHandleSets.size(); i++)
        _utilizedHandleSets[i].clear();
    _utilizedHandleSets.clear();
}

stim_t Agent::stimulateAtom(Handle h, stim_t amount)
{
    // Add atom to the map of atoms with stimulus
    // and add stimulus to it
    (*stimulatedAtoms)[h] += amount;

    // update record of total stimulus given out
    totalStimulus += amount;
    //logger().fine("%d added to totalStimulus, now %d", amount, totalStimulus);
    return totalStimulus;
}

void Agent::removeAtomStimulus(Handle h)
{
    stim_t amount;
    // if handle not in map then return
    if (stimulatedAtoms->find(h) == stimulatedAtoms->end())
        return;

    amount = (*stimulatedAtoms)[h];
    stimulatedAtoms->erase(h);

    // update record of total stimulus given out
    totalStimulus -= amount;
}

stim_t Agent::stimulateAtom(HandleSeq hs, stim_t amount)
{
    stim_t split;

    // how much to give each atom
    split = amount / hs.size();

    foreach(Handle handle, hs) {
        stimulateAtom(handle, split);
    }
    // return unused stimulus
    return amount - (split * hs.size());
}

stim_t Agent::resetStimulus()
{
    stimulatedAtoms->clear();
    // reset stimulus counter
    totalStimulus = 0;
    return totalStimulus;
}

stim_t Agent::getTotalStimulus() const
{
    return totalStimulus;
}

stim_t Agent::getAtomStimulus(Handle h) const
{
    if (stimulatedAtoms->find(h) == stimulatedAtoms->end()) {
        return 0;
    } else {
        return (*stimulatedAtoms)[h];
    }
}

<commit_msg>bugfix: cannot reference shared_ptr(this)<commit_after>/*
 * opencog/server/Agent.cc
 *
 * Copyright (C) 2008 by OpenCog Foundation
 * All Rights Reserved
 *
 * Written by Gustavo Gama <gama@vettalabs.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "Agent.h"

#include <opencog/server/CogServer.h>
#include <opencog/util/Config.h>

using namespace opencog;

Agent::Agent(CogServer& cs, const unsigned int f) : _cogserver(cs), _frequency(f)
{
    // an empty set of parameters and defaults (so that various
    // methods will still work even if none are set in this or a derived
    // class)
    static const std::string defaultConfig[] = {
        "", ""
    };
    setParameters(defaultConfig);

    stimulatedAtoms = new AtomStimHashMap();
    totalStimulus = 0;

    conn = _cogserver.getAtomSpace().atomSpaceAsync->removeAtomSignal(
            boost::bind(&Agent::atomRemoved, this, _1, _2));
}

Agent::~Agent()
{
    // give back funds
    _cogserver.getAtomSpace().getAttentionBank().updateSTIFunds(getAttentionValue().getSTI());
    _cogserver.getAtomSpace().getAttentionBank().updateLTIFunds(getAttentionValue().getLTI());

    resetUtilizedHandleSets();
    conn.disconnect();
    delete stimulatedAtoms;
}

void Agent::setParameters(const std::string* params)
{
    PARAMETERS = params;

    for (unsigned int i = 0; params[i] != ""; i += 2) {
        if (!config().has(params[i])) {
           config().set(params[i], params[i + 1]);
        }
    }
}

std::string Agent::to_string() const
{
    std::ostringstream oss;
    oss << classinfo().id;
    oss << " {\"";
    for (unsigned int i = 0; PARAMETERS[i] != ""; i += 2) {
        if (i != 0) oss << "\", \"";
        oss << PARAMETERS[i] << "\" => \"" << config()[PARAMETERS[i]];
    }
    oss << "\"}";
    return oss.str();
}

void Agent::atomRemoved(AtomSpaceImpl* a, Handle h)
{
    for (size_t i = 0; i < _utilizedHandleSets.size(); i++)
        _utilizedHandleSets[i].erase(h);
    removeAtomStimulus(h);
}

void Agent::resetUtilizedHandleSets()
{
    for (size_t i = 0; i < _utilizedHandleSets.size(); i++)
        _utilizedHandleSets[i].clear();
    _utilizedHandleSets.clear();
}

stim_t Agent::stimulateAtom(Handle h, stim_t amount)
{
    // Add atom to the map of atoms with stimulus
    // and add stimulus to it
    (*stimulatedAtoms)[h] += amount;

    // update record of total stimulus given out
    totalStimulus += amount;
    //logger().fine("%d added to totalStimulus, now %d", amount, totalStimulus);
    return totalStimulus;
}

void Agent::removeAtomStimulus(Handle h)
{
    stim_t amount;
    // if handle not in map then return
    if (stimulatedAtoms->find(h) == stimulatedAtoms->end())
        return;

    amount = (*stimulatedAtoms)[h];
    stimulatedAtoms->erase(h);

    // update record of total stimulus given out
    totalStimulus -= amount;
}

stim_t Agent::stimulateAtom(HandleSeq hs, stim_t amount)
{
    stim_t split;

    // how much to give each atom
    split = amount / hs.size();

    foreach(Handle handle, hs) {
        stimulateAtom(handle, split);
    }
    // return unused stimulus
    return amount - (split * hs.size());
}

stim_t Agent::resetStimulus()
{
    stimulatedAtoms->clear();
    // reset stimulus counter
    totalStimulus = 0;
    return totalStimulus;
}

stim_t Agent::getTotalStimulus() const
{
    return totalStimulus;
}

stim_t Agent::getAtomStimulus(Handle h) const
{
    if (stimulatedAtoms->find(h) == stimulatedAtoms->end()) {
        return 0;
    } else {
        return (*stimulatedAtoms)[h];
    }
}

<|endoftext|>


<commit_before>#include "TextureAtlas.hpp"
#include "vec.hpp"

using namespace rffalcon;

TextureAtlas::TextureAtlas(const int width, const int height, const int depth)
	: _width(width), _height(height), _depth(depth)
{
	// starter node for fitting algorithm
	// contains padding in atlas to avoid sampling artifacts
	rffalcon::ivec3 paddingNode = { { 1, 1, width - 2 } };
	_nodes.push_back(paddingNode);
	_data = new unsigned char[width * height * depth];
}

TextureAtlas::~TextureAtlas()
{
	delete [] _data;
	_data = nullptr;
}

int TextureAtlas::getWidth() const
{
	return _width;
}

int TextureAtlas::getHeight() const
{
	return _height;
}

int TextureAtlas::getDepth() const
{
	return _depth;
}

GLuint TextureAtlas::getGLTextureId() const
{
	return _glTextureId;
}

rffalcon::ivec4 TextureAtlas::getRegion(const int width, const int height)
{
	int bestY = INT_MAX;
	int bestWidth = INT_MAX;
	int bestIndex = -1;
	size_t nodeCount = _nodes.size();
	rffalcon::ivec4 region = { { -1, -1, width, height } };

	for (size_t index = 0; index < nodeCount; ++index)
	{
		int y = _fit(index, width, height);
		if (y >= 0) {
			rffalcon::ivec3 node = _nodes[index];
			if (y < bestY || (y == bestY && node.width < bestWidth))
			{
				bestY = y;
				bestIndex = index;
				bestWidth = node.width;
				region.x = node.x;
				region.y = node.yNext;
			}
		}
	}

	if (bestIndex != -1)
	{
		_addNode(region, bestIndex);
		_reduceNodes(bestIndex);
		_mergeNodes();
	}

	return region;
}

// Add node to envelope
void TextureAtlas::_addNode(rffalcon::ivec4 region, int index)
{
	rffalcon::ivec3 node;
	node.x = region.x;
	node.yNext = region.y + region.height;
	node.width = region.width;
	_nodes.insert(_nodes.begin() + index, node);
}

// Remove nodes that are no longer part of the envelope
void TextureAtlas::_reduceNodes(int startIndex)
{
	for (size_t index = startIndex + 1; index < _nodes.size(); ++index)
	{
		rffalcon::ivec3 curNode = _nodes[index];
		rffalcon::ivec3 prevNode = _nodes[index - 1];
		if (curNode.x < (prevNode.x + prevNode.width))
		{
			_nodes.erase(_nodes.begin() + index);
			int widthReduction = prevNode.x + prevNode.width - curNode.x;
			curNode.width -= widthReduction;
			if (curNode.width <= 0)
			{
				--index;
			}
			else
			{
				curNode.x += widthReduction;
				_nodes.insert(_nodes.begin() + index, curNode);
				// reduced width of the curNode, rest of envelope will be unaffected
				break;
			}
		}
		else
		{
			// rest of envelope unaffected
			break;
		}
	}
}

// Merge adjacent nodes on the envelope that have the same yNext value
void TextureAtlas::_mergeNodes()
{
	for (size_t index = 0; index < _nodes.size() - 1; ++index)
	{
		rffalcon::ivec3 curNode = _nodes[index];
		rffalcon::ivec3 nextNode = _nodes[index + 1];
		if (curNode.yNext == nextNode.yNext)
		{
			curNode.width += nextNode.width;
			_nodes.erase(_nodes.begin() + index + 1);
			--index;
		}
	}
}

int TextureAtlas::_fit(const int index, const int width, const int height)
{
	rffalcon::ivec3 node = _nodes[index];
	int x = node.x;
	int y = node.y;
	int widthLeft = width;
	int curIndex = index;
	int result = -1;

	// if adding this node left-aligned to the node at the index
	// would not go outside right edge of the texture
	if ((x + width) <= (_width - 1))
	{
		// move the new node's y position to the envelope
		y = node.yNext;
		// while this node might collide with the envelope in the x direction
		while (widthLeft > 0)
		{
			node = _nodes[curIndex];
			// if the new node collides with the envelope in the x direction
			if (node.yNext > y)
			{
				// push the new node down to the envelope
				y = node.yNext;
			}

			// if adding this node would not go outside the bottom edge of the texture
			if ((y + height) <= (_height - 1))
			{
				widthLeft -= node.width;
				++curIndex;
			}
			else
			{
				// No room to add the new node below the index node
				y = -1;
				break;
			}
		}
		result = y;
	}

	return result;
}

void TextureAtlas::setRegion(rffalcon::ivec4 region, GlyphData glyphData)
{
	int depth = getDepth();
	int width = getWidth();
	int charSize = sizeof(char);
	for (int i = 0; i < glyphData.height; ++i)
	{
		memcpy(_data + ((region.y + i) * width + region.x) * charSize * depth,
			   _data + (i * glyphData.pitch * charSize), width * charSize * depth);
	}

}

void TextureAtlas::upload()
{
	if (_glTextureId == 0)
	{
		glGenTextures(1, &_glTextureId);
	}

	glBindTexture(GL_TEXTURE_2D, _glTextureId);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	GLenum pixelDataType;
	GLint internalFormat;
	GLenum format;
	if (_depth == 4)
	{
#ifdef GL_UNSIGNED_INT_8_8_8_8_REV
		pixelDataType = GL_UNSIGNED_INT_8_8_8_8_REV;
		format = GL_BGRA;
#else
		pixelDataType = GL_UNSIGNED_BYTE;
		format = GL_RGBA;
#endif
		internalFormat = GL_RGBA;
	}
	else {
		pixelDataType = GL_UNSIGNED_BYTE;
		format = internalFormat = (_depth == 3) ? GL_RGB : GL_RED;
	}

	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, _width, _height, 0, format, pixelDataType, _data);
}<commit_msg>Copying texture data more correctly<commit_after>#include "TextureAtlas.hpp"
#include "vec.hpp"

using namespace rffalcon;

TextureAtlas::TextureAtlas(const int width, const int height, const int depth)
	: _width(width), _height(height), _depth(depth)
{
	// starter node for fitting algorithm
	// contains padding in atlas to avoid sampling artifacts
	rffalcon::ivec3 paddingNode = { { 1, 1, width - 2 } };
	_nodes.push_back(paddingNode);
	_data = new unsigned char[width * height * depth];
}

TextureAtlas::~TextureAtlas()
{
	delete [] _data;
	_data = nullptr;
}

int TextureAtlas::getWidth() const
{
	return _width;
}

int TextureAtlas::getHeight() const
{
	return _height;
}

int TextureAtlas::getDepth() const
{
	return _depth;
}

GLuint TextureAtlas::getGLTextureId() const
{
	return _glTextureId;
}

rffalcon::ivec4 TextureAtlas::getRegion(const int width, const int height)
{
	int bestY = INT_MAX;
	int bestWidth = INT_MAX;
	int bestIndex = -1;
	size_t nodeCount = _nodes.size();
	rffalcon::ivec4 region = { { -1, -1, width, height } };

	for (size_t index = 0; index < nodeCount; ++index)
	{
		int y = _fit(index, width, height);
		if (y >= 0) {
			rffalcon::ivec3 node = _nodes[index];
			if (y < bestY || (y == bestY && node.width < bestWidth))
			{
				bestY = y;
				bestIndex = index;
				bestWidth = node.width;
				region.x = node.x;
				region.y = node.yNext;
			}
		}
	}

	if (bestIndex != -1)
	{
		_addNode(region, bestIndex);
		_reduceNodes(bestIndex);
		_mergeNodes();
	}

	return region;
}

// Add node to envelope
void TextureAtlas::_addNode(rffalcon::ivec4 region, int index)
{
	rffalcon::ivec3 node;
	node.x = region.x;
	node.yNext = region.y + region.height;
	node.width = region.width;
	_nodes.insert(_nodes.begin() + index, node);
}

// Remove nodes that are no longer part of the envelope
void TextureAtlas::_reduceNodes(int startIndex)
{
	for (size_t index = startIndex + 1; index < _nodes.size(); ++index)
	{
		rffalcon::ivec3 curNode = _nodes[index];
		rffalcon::ivec3 prevNode = _nodes[index - 1];
		if (curNode.x < (prevNode.x + prevNode.width))
		{
			_nodes.erase(_nodes.begin() + index);
			int widthReduction = prevNode.x + prevNode.width - curNode.x;
			curNode.width -= widthReduction;
			if (curNode.width <= 0)
			{
				--index;
			}
			else
			{
				curNode.x += widthReduction;
				_nodes.insert(_nodes.begin() + index, curNode);
				// reduced width of the curNode, rest of envelope will be unaffected
				break;
			}
		}
		else
		{
			// rest of envelope unaffected
			break;
		}
	}
}

// Merge adjacent nodes on the envelope that have the same yNext value
void TextureAtlas::_mergeNodes()
{
	for (size_t index = 0; index < _nodes.size() - 1; ++index)
	{
		rffalcon::ivec3 curNode = _nodes[index];
		rffalcon::ivec3 nextNode = _nodes[index + 1];
		if (curNode.yNext == nextNode.yNext)
		{
			curNode.width += nextNode.width;
			_nodes.erase(_nodes.begin() + index + 1);
			--index;
		}
	}
}

int TextureAtlas::_fit(const int index, const int width, const int height)
{
	rffalcon::ivec3 node = _nodes[index];
	int x = node.x;
	int y = node.y;
	int widthLeft = width;
	int curIndex = index;
	int result = -1;

	// if adding this node left-aligned to the node at the index
	// would not go outside right edge of the texture
	if ((x + width) <= (_width - 1))
	{
		// move the new node's y position to the envelope
		y = node.yNext;
		// while this node might collide with the envelope in the x direction
		while (widthLeft > 0)
		{
			node = _nodes[curIndex];
			// if the new node collides with the envelope in the x direction
			if (node.yNext > y)
			{
				// push the new node down to the envelope
				y = node.yNext;
			}

			// if adding this node would not go outside the bottom edge of the texture
			if ((y + height) <= (_height - 1))
			{
				widthLeft -= node.width;
				++curIndex;
			}
			else
			{
				// No room to add the new node below the index node
				y = -1;
				break;
			}
		}
		result = y;
	}

	return result;
}

void TextureAtlas::setRegion(rffalcon::ivec4 region, GlyphData glyphData)
{
	int depth = getDepth();
	int charSize = sizeof(char);
	for (int i = 0; i < glyphData.height; ++i)
	{
		memcpy(_data + ((region.y + i) * getWidth() + region.x) * charSize * depth,
			   glyphData.buffer + (i * glyphData.pitch * charSize), glyphData.width * charSize * depth);
	}

}

void TextureAtlas::upload()
{
	if (_glTextureId == 0)
	{
		glGenTextures(1, &_glTextureId);
	}

	glBindTexture(GL_TEXTURE_2D, _glTextureId);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	GLenum pixelDataType;
	GLint internalFormat;
	GLenum format;
	if (_depth == 4)
	{
#ifdef GL_UNSIGNED_INT_8_8_8_8_REV
		pixelDataType = GL_UNSIGNED_INT_8_8_8_8_REV;
		format = GL_BGRA;
#else
		pixelDataType = GL_UNSIGNED_BYTE;
		format = GL_RGBA;
#endif
		internalFormat = GL_RGBA;
	}
	else {
		pixelDataType = GL_UNSIGNED_BYTE;
		format = internalFormat = (_depth == 3) ? GL_RGB : GL_RED;
	}

	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, _width, _height, 0, format, pixelDataType, _data);
}<|endoftext|>


<commit_before>//===-- dfsan.cc ----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of DataFlowSanitizer.
//
// DataFlowSanitizer runtime.  This file defines the public interface to
// DataFlowSanitizer as well as the definition of certain runtime functions
// called automatically by the compiler (specifically the instrumentation pass
// in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp).
//
// The public interface is defined in include/sanitizer/dfsan_interface.h whose
// functions are prefixed dfsan_ while the compiler interface functions are
// prefixed __dfsan_.
//===----------------------------------------------------------------------===//

#include "sanitizer/dfsan_interface.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"

#include "dfsan/dfsan.h"

using namespace __dfsan;

typedef atomic_uint16_t atomic_dfsan_label;
static const dfsan_label kInitializingLabel = -1;

static const uptr kNumLabels = 1 << (sizeof(dfsan_label) * 8);

static atomic_dfsan_label __dfsan_last_label;
static dfsan_label_info __dfsan_label_info[kNumLabels];

SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_retval_tls;
SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64];

// On Linux/x86_64, memory is laid out as follows:
//
// +--------------------+ 0x800000000000 (top of memory)
// | application memory |
// +--------------------+ 0x700000008000 (kAppAddr)
// |                    |
// |       unused       |
// |                    |
// +--------------------+ 0x200200000000 (kUnusedAddr)
// |    union table     |
// +--------------------+ 0x200000000000 (kUnionTableAddr)
// |   shadow memory    |
// +--------------------+ 0x000000010000 (kShadowAddr)
// | reserved by kernel |
// +--------------------+ 0x000000000000
//
// To derive a shadow memory address from an application memory address,
// bits 44-46 are cleared to bring the address into the range
// [0x000000008000,0x100000000000).  Then the address is shifted left by 1 to
// account for the double byte representation of shadow labels and move the
// address into the shadow memory range.  See the function shadow_for below.

typedef atomic_dfsan_label dfsan_union_table_t[kNumLabels][kNumLabels];

static const uptr kShadowAddr = 0x10000;
static const uptr kUnionTableAddr = 0x200000000000;
static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t);
static const uptr kAppAddr = 0x700000008000;

static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) {
  return &(*(dfsan_union_table_t *) kUnionTableAddr)[l1][l2];
}

// Resolves the union of two unequal labels.  Nonequality is a precondition for
// this function (the instrumentation pass inlines the equality test).
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
dfsan_label __dfsan_union(dfsan_label l1, dfsan_label l2) {
  DCHECK_NE(l1, l2);

  if (l1 == 0)
    return l2;
  if (l2 == 0)
    return l1;

  if (l1 > l2)
    Swap(l1, l2);

  atomic_dfsan_label *table_ent = union_table(l1, l2);
  // We need to deal with the case where two threads concurrently request
  // a union of the same pair of labels.  If the table entry is uninitialized,
  // (i.e. 0) use a compare-exchange to set the entry to kInitializingLabel
  // (i.e. -1) to mark that we are initializing it.
  dfsan_label label = 0;
  if (atomic_compare_exchange_strong(table_ent, &label, kInitializingLabel,
                                     memory_order_acquire)) {
    // Check whether l2 subsumes l1.  We don't need to check whether l1
    // subsumes l2 because we are guaranteed here that l1 < l2, and (at least
    // in the cases we are interested in) a label may only subsume labels
    // created earlier (i.e. with a lower numerical value).
    if (__dfsan_label_info[l2].l1 == l1 ||
        __dfsan_label_info[l2].l2 == l1) {
      label = l2;
    } else {
      label =
        atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
      CHECK_NE(label, kInitializingLabel);
      __dfsan_label_info[label].l1 = l1;
      __dfsan_label_info[label].l2 = l2;
    }
    atomic_store(table_ent, label, memory_order_release);
  } else if (label == kInitializingLabel) {
    // Another thread is initializing the entry.  Wait until it is finished.
    do {
      internal_sched_yield();
      label = atomic_load(table_ent, memory_order_acquire);
    } while (label == kInitializingLabel);
  }
  return label;
}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE
dfsan_label __dfsan_union_load(dfsan_label *ls, size_t n) {
  dfsan_label label = ls[0];
  for (size_t i = 1; i != n; ++i) {
    dfsan_label next_label = ls[i];
    if (label != next_label)
      label = __dfsan_union(label, next_label);
  }
  return label;
}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void *__dfsan_memcpy(void *dest, const void *src, size_t n) {
  dfsan_label *sdest = shadow_for(dest), *ssrc = shadow_for((void *)src);
  internal_memcpy((void *)sdest, (void *)ssrc, n * sizeof(dfsan_label));
  return internal_memcpy(dest, src, n);
}

// Like __dfsan_union, but for use from the client or custom functions.  Hence
// the equality comparison is done here before calling __dfsan_union.
SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
dfsan_union(dfsan_label l1, dfsan_label l2) {
  if (l1 == l2)
    return l1;
  return __dfsan_union(l1, l2);
}

SANITIZER_INTERFACE_ATTRIBUTE
dfsan_label dfsan_create_label(const char *desc, void *userdata) {
  dfsan_label label =
    atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
  CHECK_NE(label, kInitializingLabel);
  __dfsan_label_info[label].l1 = __dfsan_label_info[label].l2 = 0;
  __dfsan_label_info[label].desc = desc;
  __dfsan_label_info[label].userdata = userdata;
  __dfsan_retval_tls = 0;  // Ensures return value is unlabelled in the caller.
  return label;
}

SANITIZER_INTERFACE_ATTRIBUTE
void dfsan_set_label(dfsan_label label, void *addr, size_t size) {
  for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
    *labelp = label;
}

SANITIZER_INTERFACE_ATTRIBUTE
void dfsan_add_label(dfsan_label label, void *addr, size_t size) {
  for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
    if (*labelp != label)
      *labelp = __dfsan_union(*labelp, label);
}

SANITIZER_INTERFACE_ATTRIBUTE dfsan_label dfsan_get_label(long data) {
  // The label for 'data' is implicitly passed by the instrumentation pass in
  // the first element of __dfsan_arg_tls.  So we can just return it.
  __dfsan_retval_tls = 0;  // Ensures return value is unlabelled in the caller.
  return __dfsan_arg_tls[0];
}

SANITIZER_INTERFACE_ATTRIBUTE
const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) {
  __dfsan_retval_tls = 0;  // Ensures return value is unlabelled in the caller.
  return &__dfsan_label_info[label];
}

int dfsan_has_label(dfsan_label label, dfsan_label elem) {
  __dfsan_retval_tls = 0;  // Ensures return value is unlabelled in the caller.
  if (label == elem)
    return true;
  const dfsan_label_info *info = dfsan_get_label_info(label);
  if (info->l1 != 0) {
    return dfsan_has_label(info->l1, elem) || dfsan_has_label(info->l2, elem);
  } else {
    return false;
  }
}

dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc) {
  __dfsan_retval_tls = 0;  // Ensures return value is unlabelled in the caller.
  const dfsan_label_info *info = dfsan_get_label_info(label);
  if (info->l1 != 0) {
    return dfsan_has_label_with_desc(info->l1, desc) ||
           dfsan_has_label_with_desc(info->l2, desc);
  } else {
    return internal_strcmp(desc, info->desc) == 0;
  }
}

#ifdef DFSAN_NOLIBC
extern "C" void dfsan_init() {
#else
static void dfsan_init(int argc, char **argv, char **envp) {
#endif
  MmapFixedNoReserve(kShadowAddr, kUnusedAddr - kShadowAddr);

  // Protect the region of memory we don't use, to preserve the one-to-one
  // mapping from application to shadow memory. But if ASLR is disabled, Linux
  // will load our executable in the middle of our unused region. This mostly
  // works so long as the program doesn't use too much memory. We support this
  // case by disabling memory protection when ASLR is disabled.
  uptr init_addr = (uptr)&dfsan_init;
  if (!(init_addr >= kUnusedAddr && init_addr < kAppAddr))
    Mprotect(kUnusedAddr, kAppAddr - kUnusedAddr);
}

#ifndef DFSAN_NOLIBC
__attribute__((section(".preinit_array"), used))
static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init;
#endif
<commit_msg>[dfsan] Remove the unused __dfsan_memcpy function.<commit_after>//===-- dfsan.cc ----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of DataFlowSanitizer.
//
// DataFlowSanitizer runtime.  This file defines the public interface to
// DataFlowSanitizer as well as the definition of certain runtime functions
// called automatically by the compiler (specifically the instrumentation pass
// in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp).
//
// The public interface is defined in include/sanitizer/dfsan_interface.h whose
// functions are prefixed dfsan_ while the compiler interface functions are
// prefixed __dfsan_.
//===----------------------------------------------------------------------===//

#include "sanitizer/dfsan_interface.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"

#include "dfsan/dfsan.h"

using namespace __dfsan;

typedef atomic_uint16_t atomic_dfsan_label;
static const dfsan_label kInitializingLabel = -1;

static const uptr kNumLabels = 1 << (sizeof(dfsan_label) * 8);

static atomic_dfsan_label __dfsan_last_label;
static dfsan_label_info __dfsan_label_info[kNumLabels];

SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_retval_tls;
SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64];

// On Linux/x86_64, memory is laid out as follows:
//
// +--------------------+ 0x800000000000 (top of memory)
// | application memory |
// +--------------------+ 0x700000008000 (kAppAddr)
// |                    |
// |       unused       |
// |                    |
// +--------------------+ 0x200200000000 (kUnusedAddr)
// |    union table     |
// +--------------------+ 0x200000000000 (kUnionTableAddr)
// |   shadow memory    |
// +--------------------+ 0x000000010000 (kShadowAddr)
// | reserved by kernel |
// +--------------------+ 0x000000000000
//
// To derive a shadow memory address from an application memory address,
// bits 44-46 are cleared to bring the address into the range
// [0x000000008000,0x100000000000).  Then the address is shifted left by 1 to
// account for the double byte representation of shadow labels and move the
// address into the shadow memory range.  See the function shadow_for below.

typedef atomic_dfsan_label dfsan_union_table_t[kNumLabels][kNumLabels];

static const uptr kShadowAddr = 0x10000;
static const uptr kUnionTableAddr = 0x200000000000;
static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t);
static const uptr kAppAddr = 0x700000008000;

static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) {
  return &(*(dfsan_union_table_t *) kUnionTableAddr)[l1][l2];
}

// Resolves the union of two unequal labels.  Nonequality is a precondition for
// this function (the instrumentation pass inlines the equality test).
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
dfsan_label __dfsan_union(dfsan_label l1, dfsan_label l2) {
  DCHECK_NE(l1, l2);

  if (l1 == 0)
    return l2;
  if (l2 == 0)
    return l1;

  if (l1 > l2)
    Swap(l1, l2);

  atomic_dfsan_label *table_ent = union_table(l1, l2);
  // We need to deal with the case where two threads concurrently request
  // a union of the same pair of labels.  If the table entry is uninitialized,
  // (i.e. 0) use a compare-exchange to set the entry to kInitializingLabel
  // (i.e. -1) to mark that we are initializing it.
  dfsan_label label = 0;
  if (atomic_compare_exchange_strong(table_ent, &label, kInitializingLabel,
                                     memory_order_acquire)) {
    // Check whether l2 subsumes l1.  We don't need to check whether l1
    // subsumes l2 because we are guaranteed here that l1 < l2, and (at least
    // in the cases we are interested in) a label may only subsume labels
    // created earlier (i.e. with a lower numerical value).
    if (__dfsan_label_info[l2].l1 == l1 ||
        __dfsan_label_info[l2].l2 == l1) {
      label = l2;
    } else {
      label =
        atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
      CHECK_NE(label, kInitializingLabel);
      __dfsan_label_info[label].l1 = l1;
      __dfsan_label_info[label].l2 = l2;
    }
    atomic_store(table_ent, label, memory_order_release);
  } else if (label == kInitializingLabel) {
    // Another thread is initializing the entry.  Wait until it is finished.
    do {
      internal_sched_yield();
      label = atomic_load(table_ent, memory_order_acquire);
    } while (label == kInitializingLabel);
  }
  return label;
}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE
dfsan_label __dfsan_union_load(dfsan_label *ls, size_t n) {
  dfsan_label label = ls[0];
  for (size_t i = 1; i != n; ++i) {
    dfsan_label next_label = ls[i];
    if (label != next_label)
      label = __dfsan_union(label, next_label);
  }
  return label;
}

// Like __dfsan_union, but for use from the client or custom functions.  Hence
// the equality comparison is done here before calling __dfsan_union.
SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
dfsan_union(dfsan_label l1, dfsan_label l2) {
  if (l1 == l2)
    return l1;
  return __dfsan_union(l1, l2);
}

SANITIZER_INTERFACE_ATTRIBUTE
dfsan_label dfsan_create_label(const char *desc, void *userdata) {
  dfsan_label label =
    atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
  CHECK_NE(label, kInitializingLabel);
  __dfsan_label_info[label].l1 = __dfsan_label_info[label].l2 = 0;
  __dfsan_label_info[label].desc = desc;
  __dfsan_label_info[label].userdata = userdata;
  __dfsan_retval_tls = 0;  // Ensures return value is unlabelled in the caller.
  return label;
}

SANITIZER_INTERFACE_ATTRIBUTE
void dfsan_set_label(dfsan_label label, void *addr, size_t size) {
  for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
    *labelp = label;
}

SANITIZER_INTERFACE_ATTRIBUTE
void dfsan_add_label(dfsan_label label, void *addr, size_t size) {
  for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
    if (*labelp != label)
      *labelp = __dfsan_union(*labelp, label);
}

SANITIZER_INTERFACE_ATTRIBUTE dfsan_label dfsan_get_label(long data) {
  // The label for 'data' is implicitly passed by the instrumentation pass in
  // the first element of __dfsan_arg_tls.  So we can just return it.
  __dfsan_retval_tls = 0;  // Ensures return value is unlabelled in the caller.
  return __dfsan_arg_tls[0];
}

SANITIZER_INTERFACE_ATTRIBUTE
const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) {
  __dfsan_retval_tls = 0;  // Ensures return value is unlabelled in the caller.
  return &__dfsan_label_info[label];
}

int dfsan_has_label(dfsan_label label, dfsan_label elem) {
  __dfsan_retval_tls = 0;  // Ensures return value is unlabelled in the caller.
  if (label == elem)
    return true;
  const dfsan_label_info *info = dfsan_get_label_info(label);
  if (info->l1 != 0) {
    return dfsan_has_label(info->l1, elem) || dfsan_has_label(info->l2, elem);
  } else {
    return false;
  }
}

dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc) {
  __dfsan_retval_tls = 0;  // Ensures return value is unlabelled in the caller.
  const dfsan_label_info *info = dfsan_get_label_info(label);
  if (info->l1 != 0) {
    return dfsan_has_label_with_desc(info->l1, desc) ||
           dfsan_has_label_with_desc(info->l2, desc);
  } else {
    return internal_strcmp(desc, info->desc) == 0;
  }
}

#ifdef DFSAN_NOLIBC
extern "C" void dfsan_init() {
#else
static void dfsan_init(int argc, char **argv, char **envp) {
#endif
  MmapFixedNoReserve(kShadowAddr, kUnusedAddr - kShadowAddr);

  // Protect the region of memory we don't use, to preserve the one-to-one
  // mapping from application to shadow memory. But if ASLR is disabled, Linux
  // will load our executable in the middle of our unused region. This mostly
  // works so long as the program doesn't use too much memory. We support this
  // case by disabling memory protection when ASLR is disabled.
  uptr init_addr = (uptr)&dfsan_init;
  if (!(init_addr >= kUnusedAddr && init_addr < kAppAddr))
    Mprotect(kUnusedAddr, kAppAddr - kUnusedAddr);
}

#ifndef DFSAN_NOLIBC
__attribute__((section(".preinit_array"), used))
static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init;
#endif
<|endoftext|>


<commit_before>#include <iostream>
#include "time.h"
#include <string>
#include "novoht.h"
#include <cstdlib>
#include <cstddef>
#include <sys/time.h>//
//#include "meta.pb.h"
#define KEY_LEN 32
#define VAL_LEN 128
using namespace std;
struct timeval tp;
double diffclock(clock_t clock1, clock_t clock2){
   double clock_ts=clock1-clock2;
   double diffms=(clock_ts*1000)/CLOCKS_PER_SEC;
   return diffms;
}
double getTime_usec() {
   gettimeofday(&tp, NULL);
   return static_cast<double>(tp.tv_sec) * 1E6+ static_cast<double>(tp.tv_usec);
}
string randomString(int len) {
   string s(len, ' ');
   srand(/*getpid()*/ clock() + getTime_usec());
   static const char alphanum[] = "0123456789"
       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
       "abcdefghijklmnopqrstuvwxyz";
   for (int i = 0; i < len; ++i) {
      s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
   }
   return s;
}
double testInsert(NoVoHT &map, string keys[], string vals[], int l){
   int fails =0;
   cout << "0\% Complete\r";
   cout.flush();
   clock_t a=clock();
   for (int t = 0; t<l; t++){
      fails += map.put(keys[t], vals[t]);
      if ((t+1)%10000 == 0)cout << t*100/l << "\% Complete\r";
   }

   clock_t b=clock();
   cout << "100\% Complete with " << fails << " not inserted" << endl;
   return diffclock(b,a);
   ;
}
double testGet(NoVoHT &map, string keys[], string vals[], int l){
   int fails = 0;
   cout << "0\% Complete\r";
   clock_t a=clock();
   for (int t=0; t<l; t++){
      if (!map.get(keys[t])) fails++;
      else if (map.get(keys[t])->compare(vals[t]) != 0)fails++;
      if ((t+1)%10000 == 0)cout << t*100/l << "\% Complete\r";
   }
   clock_t b=clock();
   cout << "100\% Complete with " << fails << " not found" << endl;
   return diffclock(b,a);
}
double testRemove(NoVoHT &map, string keys[], int l){
   int fails = 0;
   cout << "0\% Complete\r";
   clock_t a=clock();
   for (int t=0; t<l; t++){
      map.remove(keys[t]);
      if ((t+1)%10000 == 0)cout << t*100/l << "\% Complete\r";
   }
   clock_t b=clock();
   cout << "100\% Complete with " << fails << " not found" << endl;
   return diffclock(b,a);
}
int main(int argc, char *argv[]){
   cout << "\nInitializing key-value pairs for testing\n";
   cout << "0\%\r";
   int size = atoi(argv[1]);
   string* keys = new string[size];
   string* vals = new string[size];
   /*for (int t=0;
     t<size;
     t++){
     Package package, package_ret;
     string key = randomString(25);
   //as keypackage.set_virtualpath(key);
   package.set_isdir(true);
   package.set_replicano(5);
   package.set_operation(3);
   package.set_realfullpath("Some-Real-longer-longer-and-longer-Paths--------");
   package.add_listitem("item-----1");
   package.add_listitem("item-----2");
   package.add_listitem("item-----3");
   package.add_listitem("item-----4");
   package.add_listitem("item-----5");
   string value = package.SerializeAsString();
   keys[t] = key;
   vals[t] = value;
   }
   */
   for (int t=0; t<size; t++){
      keys[t] = randomString(KEY_LEN);
      vals[t] = randomString(VAL_LEN);
      if(t%1000 == 0)cout << t*100/size << "\%\r";
   }
   cout << "Done\n" << endl;
   NoVoHT map ("fbench.data", 1000000, 10000);
   //NoVoHT map ("", 10000000, -1);
   //NoVoHT map ("", 1000000, 10000, .7);
   //NoVoHT map ("", 1000000, -1);
   //NoVoHT map ("/dev/shm/fbench.data", 1000000, -1);
   double ins, ret, rem;
   cout << "Testing Insertion: Inserting " << size << " elements" << endl;
   ins = testInsert(map, keys,vals,size);
   cout << "Testing Retrieval: Retrieving " << size << " elements" << endl;
   ret = testGet(map,keys,vals,size);
   cout << "Testing Removal: Removing " << size << " elements" << endl;
   rem = testRemove(map,keys,size);
   cout << "\nInsertion done in " << ins << " milliseconds" << endl;
   cout << "Retrieval done in " << ret << " milliseconds" << endl;
   cout << "Removal done in " << rem << " milliseconds" << endl;
   delete [] keys;
   delete [] vals;
   return 0;
}

<commit_msg>	modified:   fbench.cxx<commit_after>#include <iostream>
#include "time.h"
#include <string>
#include "novoht.h"
#include <cstdlib>
#include <cstddef>
#include <sys/time.h>//
//#include "meta.pb.h"
#define KEY_LEN 32
#define VAL_LEN 128
using namespace std;
struct timeval tp;
double diffclock(clock_t clock1, clock_t clock2){
   double clock_ts=clock1-clock2;
   double diffms=(clock_ts*1000)/CLOCKS_PER_SEC;
   return diffms;
}
double getTime_usec() {
   gettimeofday(&tp, NULL);
   return static_cast<double>(tp.tv_sec) * 1E6+ static_cast<double>(tp.tv_usec);
}
string randomString(int len) {
   string s(len, ' ');
   srand(/*getpid()*/ clock() + getTime_usec());
   static const char alphanum[] = "0123456789"
       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
       "abcdefghijklmnopqrstuvwxyz";
   for (int i = 0; i < len; ++i) {
      s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
   }
   return s;
}
double testInsert(NoVoHT &map, string keys[], string vals[], int l){
   int fails =0;
   cout << "0\% Complete\r";
   cout.flush();
   clock_t a=clock();
   for (int t = 0; t<l; t++){
      fails += map.put(keys[t], vals[t]);
      if ((t+1)%1000 == 0)cout << t*100/l << "\% Complete\r";
   }

   clock_t b=clock();
   cout << "100\% Complete with " << fails << " not inserted" << endl;
   return diffclock(b,a);
   ;
}
double testGet(NoVoHT &map, string keys[], string vals[], int l){
   int fails = 0;
   cout << "0\% Complete\r";
   clock_t a=clock();
   for (int t=0; t<l; t++){
      if (!map.get(keys[t])) fails++;
      else if (map.get(keys[t])->compare(vals[t]) != 0)fails++;
      if ((t+1)%1000 == 0)cout << t*100/l << "\% Complete\r";
   }
   clock_t b=clock();
   cout << "100\% Complete with " << fails << " not found" << endl;
   return diffclock(b,a);
}
double testRemove(NoVoHT &map, string keys[], int l){
   int fails = 0;
   cout << "0\% Complete\r";
   clock_t a=clock();
   for (int t=0; t<l; t++){
      map.remove(keys[t]);
      if ((t+1)%1000 == 0)cout << t*100/l << "\% Complete\r";
   }
   clock_t b=clock();
   cout << "100\% Complete with " << fails << " not found" << endl;
   return diffclock(b,a);
}
int main(int argc, char *argv[]){
   cout << "\nInitializing key-value pairs for testing\n";
   cout << "0\%\r";
   int size = atoi(argv[1]);
   string* keys = new string[size];
   string* vals = new string[size];
   /*for (int t=0;
     t<size;
     t++){
     Package package, package_ret;
     string key = randomString(25);
   //as keypackage.set_virtualpath(key);
   package.set_isdir(true);
   package.set_replicano(5);
   package.set_operation(3);
   package.set_realfullpath("Some-Real-longer-longer-and-longer-Paths--------");
   package.add_listitem("item-----1");
   package.add_listitem("item-----2");
   package.add_listitem("item-----3");
   package.add_listitem("item-----4");
   package.add_listitem("item-----5");
   string value = package.SerializeAsString();
   keys[t] = key;
   vals[t] = value;
   }
   */
   for (int t=0; t<size; t++){
      keys[t] = randomString(KEY_LEN);
      vals[t] = randomString(VAL_LEN);
      if(t%1000 == 0)cout << t*100/size << "\%\r";
   }
   cout << "Done\n" << endl;
   NoVoHT map ("fbench.data", 1000000, 10000);
   //NoVoHT map ("", 10000000, -1);
   //NoVoHT map ("", 1000000, 10000, .7);
   //NoVoHT map ("", 1000000, -1);
   //NoVoHT map ("/dev/shm/fbench.data", 1000000, -1);
   double ins, ret, rem;
   cout << "Testing Insertion: Inserting " << size << " elements" << endl;
   ins = testInsert(map, keys,vals,size);
   cout << "Testing Retrieval: Retrieving " << size << " elements" << endl;
   ret = testGet(map,keys,vals,size);
   cout << "Testing Removal: Removing " << size << " elements" << endl;
   rem = testRemove(map,keys,size);
   cout << "\nInsertion done in " << ins << " milliseconds" << endl;
   cout << "Retrieval done in " << ret << " milliseconds" << endl;
   cout << "Removal done in " << rem << " milliseconds" << endl;
   delete [] keys;
   delete [] vals;
   return 0;
}

<|endoftext|>


<commit_before>#include <QQuickWindow>
#include <QDebug>

#include "myfilesavedialog.h"

MyFileSaveDialog::MyFileSaveDialog(QQuickItem *parent) :
    QQuickItem(parent)
  , m_modality(Qt::WindowModal)
  , m_options(QSharedPointer<QFileDialogOptions>(new QFileDialogOptions()))
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
    qDebug() << "Working with Qt 5.2";
#else
    qDebug() << "Working with Qt 5.1";
#endif

    m_dlgHelper = init_helper();

    connect(m_dlgHelper, SIGNAL(accept()), this, SLOT(accept()));
    connect(m_dlgHelper, SIGNAL(reject()), this, SLOT(reject()));
}

MyFileSaveDialog::~MyFileSaveDialog()
{
    if (m_dlgHelper)
        m_dlgHelper->hide();
    delete m_dlgHelper;
}

QUrl MyFileSaveDialog::fileUrl() const
{
    return fileUrl_;
}

void MyFileSaveDialog::setFileUrl(QUrl fileUrl)
{
    if (fileUrl_ != fileUrl)
    {
        fileUrl_ = fileUrl;
        emit fileUrlChanged();
    }
}

QString MyFileSaveDialog::filename() const
{
    return filename_;
}

void MyFileSaveDialog::setFilename(QString filename)
{
    if (filename_ != filename)
    {
        filename_ = filename;
        emit filenameChanged();
    }
}

QString MyFileSaveDialog::title() const
{
    return title_;
}

void MyFileSaveDialog::setTitle(QString title)
{
    if (title_ != title)
    {
        title_ = title;
        emit titleChanged();
    }
}

QPlatformFileDialogHelper* MyFileSaveDialog::init_helper()
{
    m_dlgHelper = static_cast<QPlatformFileDialogHelper*>(QGuiApplicationPrivate::platformTheme()->createPlatformDialogHelper(QPlatformTheme::FileDialog));
    if (!m_dlgHelper)
        return NULL;

    return m_dlgHelper;
}

void MyFileSaveDialog::open()
{
    QQuickItem *me = this;
    Q_ASSERT(me);

    QQuickItem *parent = me->parentItem();
    Q_ASSERT(parent);

    QQuickWindow *window = parent->window();
    Q_ASSERT(window);

    m_parentWindow = window;

    m_options->setFileMode(QFileDialogOptions::AnyFile);
    m_options->setAcceptMode(QFileDialogOptions::AcceptSave);
    m_options->setWindowTitle(title());

    /*
     * Mac:
     * Set filename incl. directory via setInitiallySelectedFiles()
     *
     * Windows:
     * Set filename via setInitiallySelectedFiles() and let Windows choose the directory.
     * Default directory: C:\\Users\XYZ\Downloads
     *
     * Gnome:
     * Set directory via QPlatformFileDialogHelper::setDirectory() and leave
     * filename empty, since QGtk2FileDialogHelper can not set non-existing filenames.
     *
     */
#ifdef Q_OS_MACX // Use Q_OS_MACX for Qt 5.1+ code and Q_OS_OSX for Qt 5.2+ code.
    QString initialSelection = QFileInfo(QDir::homePath(), filename()).absoluteFilePath();
    qDebug() << "Initial file:" << initialSelection;
    #if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
        m_options->setInitiallySelectedFiles(QList<QUrl>() << QUrl::fromLocalFile(initialSelection));
    #else
        m_options->setInitiallySelectedFiles(QStringList(initialSelection));
    #endif
#endif
#ifdef Q_OS_WIN
    qDebug() << "Initial filename:" << filename();
    #if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
        m_options->setInitiallySelectedFiles(QList<QUrl>() << QUrl::fromLocalFile(filename()));
    #else
        m_options->setInitiallySelectedFiles(QStringList(filename()));
    #endif
#endif
#ifdef Q_OS_LINUX
    qDebug() << "Initial directory:" << QDir::homePath();
    #if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
        m_dlgHelper->setDirectory(QUrl::fromLocalFile(QDir::homePath()));
    #else
        m_dlgHelper->setDirectory(QDir::homePath());
    #endif
#endif

    m_dlgHelper->setOptions(m_options);
    m_dlgHelper->setFilter(); // applyOptions();

    Qt::WindowFlags flags = Qt::Dialog;
    if (!title().isEmpty()) flags |= Qt::WindowTitleHint;

    m_visible = m_dlgHelper->show(flags, m_modality, m_parentWindow);
}

void MyFileSaveDialog::close()
{
    m_dlgHelper->hide();
    m_visible = false;
}

void MyFileSaveDialog::accept()
{
    m_dlgHelper->hide();

#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
    QList<QUrl> selectedUrls = m_dlgHelper->selectedFiles();
    if ( selectedUrls.count() )
    {
        setFileUrl(selectedUrls.at(0));
    }
#else
    QStringList selectedFiles = m_dlgHelper->selectedFiles();
    if ( selectedFiles.count() )
    {
        setFileUrl(QUrl::fromLocalFile(selectedFiles.at(0)));
    }
#endif

    emit accepted();
}

void MyFileSaveDialog::reject()
{
    m_dlgHelper->hide();
    emit rejected();
}
<commit_msg>Skip trivial step to get QQuickItem `this`<commit_after>#include <QQuickWindow>
#include <QDebug>

#include "myfilesavedialog.h"

MyFileSaveDialog::MyFileSaveDialog(QQuickItem *parent) :
    QQuickItem(parent)
  , m_modality(Qt::WindowModal)
  , m_options(QSharedPointer<QFileDialogOptions>(new QFileDialogOptions()))
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
    qDebug() << "Working with Qt 5.2";
#else
    qDebug() << "Working with Qt 5.1";
#endif

    m_dlgHelper = init_helper();

    connect(m_dlgHelper, SIGNAL(accept()), this, SLOT(accept()));
    connect(m_dlgHelper, SIGNAL(reject()), this, SLOT(reject()));
}

MyFileSaveDialog::~MyFileSaveDialog()
{
    if (m_dlgHelper)
        m_dlgHelper->hide();
    delete m_dlgHelper;
}

QUrl MyFileSaveDialog::fileUrl() const
{
    return fileUrl_;
}

void MyFileSaveDialog::setFileUrl(QUrl fileUrl)
{
    if (fileUrl_ != fileUrl)
    {
        fileUrl_ = fileUrl;
        emit fileUrlChanged();
    }
}

QString MyFileSaveDialog::filename() const
{
    return filename_;
}

void MyFileSaveDialog::setFilename(QString filename)
{
    if (filename_ != filename)
    {
        filename_ = filename;
        emit filenameChanged();
    }
}

QString MyFileSaveDialog::title() const
{
    return title_;
}

void MyFileSaveDialog::setTitle(QString title)
{
    if (title_ != title)
    {
        title_ = title;
        emit titleChanged();
    }
}

QPlatformFileDialogHelper* MyFileSaveDialog::init_helper()
{
    m_dlgHelper = static_cast<QPlatformFileDialogHelper*>(QGuiApplicationPrivate::platformTheme()->createPlatformDialogHelper(QPlatformTheme::FileDialog));
    if (!m_dlgHelper)
        return NULL;

    return m_dlgHelper;
}

void MyFileSaveDialog::open()
{
    QQuickItem *parent = this->parentItem();
    Q_ASSERT(parent);

    QQuickWindow *window = parent->window();
    Q_ASSERT(window);

    m_parentWindow = window;

    m_options->setFileMode(QFileDialogOptions::AnyFile);
    m_options->setAcceptMode(QFileDialogOptions::AcceptSave);
    m_options->setWindowTitle(title());

    /*
     * Mac:
     * Set filename incl. directory via setInitiallySelectedFiles()
     *
     * Windows:
     * Set filename via setInitiallySelectedFiles() and let Windows choose the directory.
     * Default directory: C:\\Users\XYZ\Downloads
     *
     * Gnome:
     * Set directory via QPlatformFileDialogHelper::setDirectory() and leave
     * filename empty, since QGtk2FileDialogHelper can not set non-existing filenames.
     *
     */
#ifdef Q_OS_MACX // Use Q_OS_MACX for Qt 5.1+ code and Q_OS_OSX for Qt 5.2+ code.
    QString initialSelection = QFileInfo(QDir::homePath(), filename()).absoluteFilePath();
    qDebug() << "Initial file:" << initialSelection;
    #if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
        m_options->setInitiallySelectedFiles(QList<QUrl>() << QUrl::fromLocalFile(initialSelection));
    #else
        m_options->setInitiallySelectedFiles(QStringList(initialSelection));
    #endif
#endif
#ifdef Q_OS_WIN
    qDebug() << "Initial filename:" << filename();
    #if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
        m_options->setInitiallySelectedFiles(QList<QUrl>() << QUrl::fromLocalFile(filename()));
    #else
        m_options->setInitiallySelectedFiles(QStringList(filename()));
    #endif
#endif
#ifdef Q_OS_LINUX
    qDebug() << "Initial directory:" << QDir::homePath();
    #if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
        m_dlgHelper->setDirectory(QUrl::fromLocalFile(QDir::homePath()));
    #else
        m_dlgHelper->setDirectory(QDir::homePath());
    #endif
#endif

    m_dlgHelper->setOptions(m_options);
    m_dlgHelper->setFilter(); // applyOptions();

    Qt::WindowFlags flags = Qt::Dialog;
    if (!title().isEmpty()) flags |= Qt::WindowTitleHint;

    m_visible = m_dlgHelper->show(flags, m_modality, m_parentWindow);
}

void MyFileSaveDialog::close()
{
    m_dlgHelper->hide();
    m_visible = false;
}

void MyFileSaveDialog::accept()
{
    m_dlgHelper->hide();

#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
    QList<QUrl> selectedUrls = m_dlgHelper->selectedFiles();
    if ( selectedUrls.count() )
    {
        setFileUrl(selectedUrls.at(0));
    }
#else
    QStringList selectedFiles = m_dlgHelper->selectedFiles();
    if ( selectedFiles.count() )
    {
        setFileUrl(QUrl::fromLocalFile(selectedFiles.at(0)));
    }
#endif

    emit accepted();
}

void MyFileSaveDialog::reject()
{
    m_dlgHelper->hide();
    emit rejected();
}
<|endoftext|>


<commit_before>#ifdef __WAND__
target[name[figure.o] type[object]]
#endif

#include "figure.h"
#include "output.h"
#include "macro.h"
#include "commentprocessor.h"

#include <herbs/intformat/intformat.h>
#include <herbs/exceptionmissing/exceptionmissing.h>

void Doxymax::Figure::expand(const Macro& macro,CommentProcessor& processor)
	{
	if(macro.args.length()<3)
		{throw Herbs::ExceptionMissing(___FILE__,__LINE__);}

	Herbs::String str_out(128);
	str_out
		.append(STR("\\anchor ")).append(macro.args[2]).append(CHAR(' '))
		.append(STR("
"))
		.append(STR("3)
		{
		str_out.append(STR(" width=\"")).append(macro.args[3])
			.append(CHAR('"'));
		}

	if(macro.args.length()>4)
		{
		str_out.append(STR(" height=\"")).append(macro.args[4])
			.append(CHAR('"'));
		}

	size_t n=processor.labelGet(macro.args[2]);
	if(n==0)
		{
		n=processor.counterGet(STR("Figure"));
		++n;
		processor.labelSet(macro.args[2],n);
		}
	str_out.append(STR("/>
Figure "))
		.append(Herbs::IntFormat<size_t>(n))
		.append(STR(": "))
		.append(macro.args[1])
		.append(STR("

"));
	processor.counterSet(STR("Figure"),n);

	print(str_out);
	}
<commit_msg>Added hyperlink to image file in the figure macro<commit_after>#ifdef __WAND__
target[name[figure.o] type[object]]
#endif

#include "figure.h"
#include "output.h"
#include "macro.h"
#include "commentprocessor.h"

#include <herbs/intformat/intformat.h>
#include <herbs/exceptionmissing/exceptionmissing.h>

void Doxymax::Figure::expand(const Macro& macro,CommentProcessor& processor)
	{
	if(macro.args.length()<3)
		{throw Herbs::ExceptionMissing(___FILE__,__LINE__);}

	Herbs::String str_out(128);
	str_out
		.append(STR("\\anchor ")).append(macro.args[2]).append(CHAR(' '))
		.append(STR("
"))
		.append(STR("3)
		{
		str_out.append(STR(" width=\"")).append(macro.args[3])
			.append(CHAR('"'));
		}

	if(macro.args.length()>4)
		{
		str_out.append(STR(" height=\"")).append(macro.args[4])
			.append(CHAR('"'));
		}

	size_t n=processor.labelGet(macro.args[2]);
	if(n==0)
		{
		n=processor.counterGet(STR("Figure"));
		++n;
		processor.labelSet(macro.args[2],n);
		}
	str_out.append(STR("/>
Figure "))
		.append(Herbs::IntFormat<size_t>(n))
		.append(STR(": "))
		.append(macro.args[1])
		.append(STR("

"));
	processor.counterSet(STR("Figure"),n);

	print(str_out);
	}
<|endoftext|>