<commit_before>/*
Copyright (c) 2016 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 "library/trace.h"
#include "library/locals.h"
#include "library/app_builder.h"
#include "library/equations_compiler/util.h"
#include "library/equations_compiler/structural_rec.h"

namespace lean {
#define trace_struct(Code) lean_trace(name({"eqn_compiler", "structural_rec"}), scope_trace_env _scope1(m_ctx.env(), m_ctx); Code)

struct structural_rec_fn {
    type_context & m_ctx;
    structural_rec_fn(type_context & ctx):m_ctx(ctx) {}

    /** \brief Auxiliary object for checking whether recursive application are
        structurally smaller or not */
    struct check_rhs_fn {
        type_context & m_ctx;
        expr           m_lhs;
        expr           m_fn;
        expr           m_pattern;
        unsigned       m_arg_idx;

        check_rhs_fn(type_context & ctx, expr const & lhs, expr const & fn, expr const & pattern, unsigned arg_idx):
            m_ctx(ctx), m_lhs(lhs), m_fn(fn), m_pattern(pattern), m_arg_idx(arg_idx) {}

        bool is_constructor(expr const & e) const {
            return static_cast<bool>(eqns_env_interface(m_ctx).is_constructor(e));
        }

        /** \brief Return true iff \c s is structurally smaller than \c t OR equal to \c t */
        bool is_le(expr const & s, expr const & t) {
            return m_ctx.is_def_eq(s, t) || is_lt(s, t);
        }

        /** Return true iff \c s is structurally smaller than \c t */
        bool is_lt(expr s, expr const & t) {
            s = m_ctx.whnf(s);
            if (is_app(s)) {
                expr const & s_fn = get_app_fn(s);
                if (!is_constructor(s_fn))
                    return is_lt(s_fn, t); // f < t ==> s := f a_1 ... a_n < t
            }
            buffer<expr> t_args;
            expr const & t_fn = get_app_args(t, t_args);
            if (!is_constructor(t_fn))
                return false;
            return std::any_of(t_args.begin(), t_args.end(),
                               [&](expr const & t_arg) { return is_le(s, t_arg); });
        }

        /** \brief Return true iff all recursive applications in \c e are structurally smaller than \c m_pattern. */
        bool check_rhs(expr const & e) {
            switch (e.kind()) {
            case expr_kind::Var:   case expr_kind::Meta:
            case expr_kind::Local: case expr_kind::Constant:
            case expr_kind::Sort:
                return true;
            case expr_kind::Macro:
                for (unsigned i = 0; i < macro_num_args(e); i++)
                    if (!check_rhs(macro_arg(e, i)))
                        return false;
                return true;
            case expr_kind::App: {
                buffer<expr> args;
                expr const & fn = get_app_args(e, args);
                if (!check_rhs(fn))
                    return false;
                for (unsigned i = 0; i < args.size(); i++)
                    if (!check_rhs(args[i]))
                        return false;
                if (is_local(fn) && mlocal_name(fn) == mlocal_name(m_fn)) {
                    /* recusive application */
                    if (m_arg_idx < args.size()) {
                        expr const & arg = args[m_arg_idx];
                        /* arg must be structurally smaller than m_pattern */
                        if (!is_lt(arg, m_pattern)) {
                            trace_struct(tout() << "structural recursion on argument #" << (m_arg_idx+1) << " was not used "
                                         << "for '" << m_fn << "'\nargument #" << (m_arg_idx+1)
                                         << " in the application\n  "
                                         << e << "\nis not structurally smaller than the one occurring in "
                                         << "the equation left-hand-side\n  "
                                         << m_lhs << "\n";);
                            return false;
                        }
                    } else {
                        /* function is not fully applied */
                        trace_struct(tout() << "structural recursion on argument #" << (m_arg_idx+1) << " was not used "
                                     << "for '" << m_fn << "' because of the partial application\n  "
                                     << e << "\n";);
                        return false;
                    }
                }
                return true;
            }
            case expr_kind::Let:
                if (!check_rhs(let_value(e))) {
                    return false;
                } else {
                    type_context::tmp_locals locals(m_ctx);
                    return check_rhs(instantiate(let_body(e), locals.push_local_from_let(e)));
                }
            case expr_kind::Lambda:
            case expr_kind::Pi:
                if (!check_rhs(binding_domain(e))) {
                    return false;
                } else {
                    type_context::tmp_locals locals(m_ctx);
                    return check_rhs(instantiate(binding_body(e), locals.push_local_from_binding(e)));
                }
            }
            lean_unreachable();
        }

        bool operator()(expr const & e) {
            return check_rhs(e);
        }
    };

    bool check_rhs(expr const & lhs, expr const & fn, expr pattern, unsigned arg_idx, expr const & rhs) {
        pattern = m_ctx.whnf(pattern);
        return check_rhs_fn(m_ctx, lhs, fn, pattern, arg_idx)(rhs);
    }

    bool check_eq(expr const & eqn, unsigned arg_idx) {
        unpack_eqn ue(m_ctx, eqn);
        buffer<expr> args;
        expr const & fn  = get_app_args(ue.lhs(), args);
        return check_rhs(ue.lhs(), fn, args[arg_idx], arg_idx, ue.rhs());
    }

    static bool depends_on_locals(expr const & e, type_context::tmp_locals const & locals) {
        return depends_on_any(e, locals.as_buffer().size(), locals.as_buffer().data());
    }

    bool check_arg_type(unpack_eqns const & ues, unsigned arg_idx) {
        type_context::tmp_locals locals(m_ctx);
        /* We can only use structural recursion on arg_idx IF
           1- Type is an inductive datatype with support for the brec_on construction.
           2- Type parameters do not depend on other arguments of the function being defined. */
        expr fn      = ues.get_fn(0);
        expr fn_type = m_ctx.infer(fn);
        for (unsigned i = 0; i < arg_idx; i++) {
            fn_type = m_ctx.whnf(fn_type);
            if (!is_pi(fn_type)) throw_ill_formed_eqns();
            fn_type = instantiate(binding_body(fn_type), locals.push_local_from_binding(fn_type));
        }
        if (!is_pi(fn_type)) throw_ill_formed_eqns();
        expr arg_type = binding_domain(fn_type);
        buffer<expr> I_args;
        expr I        = get_app_args(arg_type, I_args);
        if (!eqns_env_interface(m_ctx).is_inductive(I)) {
            trace_struct(tout() << "structural recursion on argument #" << (arg_idx+1) << " was not used "
                         << "for '" << fn << "' because type is not inductive\n  "
                         << arg_type << "\n";);
            return false;
        }
        if (!m_ctx.env().find(name(const_name(I), "brec_on"))) {
            trace_struct(tout() << "structural recursion on argument #" << (arg_idx+1) << " was not used "
                         << "for '" << fn << "' because the inductive type '" << I << "' does have brec_on recursor\n  "
                         << arg_type << "\n";);
            return false;
        }
        unsigned nindices = eqns_env_interface(m_ctx).get_inductive_num_indices(const_name(I));
        if (nindices > 0) {
            trace_struct(tout() << "structural recursion on argument #" << (arg_idx+1) << " was not used "
                         << "for '" << fn << "' because the inductive type '" << I << "' is an indexed family\n  "
                         << arg_type << "\n";);
            return false;
        }
        if (depends_on_locals(arg_type, locals)) {
            trace_struct(tout() << "structural recursion on argument #" << (arg_idx+1) << " was not used "
                         << "for '" << fn << "' because type parameter depends on previous arguments\n  "
                         << arg_type << "\n";);
            return false;
        }
        return true;
    }

    optional<unsigned> find_rec_arg(unpack_eqns const & ues) {
        buffer<expr> const & eqns = ues.get_eqns_of(0);
        unsigned arity = ues.get_arity_of(0);
        for (unsigned i = 0; i < arity; i++) {
            if (check_arg_type(ues, i)) {
                bool ok = true;
                for (expr const & eqn : eqns) {
                    if (!check_eq(eqn, i)) {
                        ok = false;
                        break;
                    }
                }
                if (ok) return optional<unsigned>(i);
            }
        }
        return optional<unsigned>();
    }

    expr mk_new_fn_type(unpack_eqns const & ues, unsigned arg_idx) {
        type_context::tmp_locals locals(m_ctx);
        expr fn        = ues.get_fn(0);
        expr fn_type   = m_ctx.infer(fn);
        unsigned arity = ues.get_arity_of(0);
        expr rec_arg;
        buffer<expr> other_args;
        for (unsigned i = 0; i < arity; i++) {
            fn_type = m_ctx.whnf(fn_type);
            if (!is_pi(fn_type)) throw_ill_formed_eqns();
            expr arg = locals.push_local_from_binding(fn_type);
            if (i == arg_idx) {
                rec_arg = arg;
            } else {
                other_args.push_back(arg);
            }
            fn_type  = instantiate(binding_body(fn_type), arg);
        }
        expr  motive = m_ctx.mk_pi(other_args, fn_type);
        level u      = get_level(m_ctx, motive);
        motive       = m_ctx.mk_lambda(rec_arg, motive);
        buffer<expr> I_args;
        expr I = get_app_args(m_ctx.infer(rec_arg), I_args);
        lean_assert(is_constant(I));
        buffer<level> below_lvls;
        below_lvls.push_back(u);
        for (level const & v : const_levels(I))
            below_lvls.push_back(v);
        expr below  = mk_app(mk_constant(name(const_name(I), "below"), to_list(below_lvls)), motive, rec_arg);
        locals.push_local("_F", below);
        return locals.mk_pi(fn_type);
    }

    optional<expr> operator()(expr const & e, unsigned & arg_idx) {
        unpack_eqns ues(m_ctx, e);
        if (ues.get_num_fns() != 1) {
            trace_struct(tout() << "structural recursion is not supported for mutually recursive functions:";
                         for (unsigned i = 0; i < ues.get_num_fns(); i++)
                             tout() << " " << ues.get_fn(i);
                         tout() << "\n";);
            return none_expr();
        }
        optional<unsigned> r = find_rec_arg(ues);
        if (!r) return none_expr();
        arg_idx = *r;
        trace_struct(tout() << "using structural recursion on argument #" << (arg_idx+1) <<
                     " for '" << ues.get_fn(0) << "'\n";);
        expr new_fn_type = mk_new_fn_type(ues, arg_idx);

        trace_struct(tout() << "new function type: " << new_fn_type << "\n";);

        // TODO(Leo)

        return some_expr(ues.repack());
    }
};

optional<expr> try_structural_rec(type_context & ctx, expr const & e, unsigned & arg_idx) {
    return structural_rec_fn(ctx)(e, arg_idx);
}

void initialize_structural_rec() {
    register_trace_class({"eqn_compiler", "structural_rec"});
}
void finalize_structural_rec() {}
}
<commit_msg>feat(library/equations_compiler/structural_rec): finish structural recursion step<commit_after>/*
Copyright (c) 2016 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 "library/trace.h"
#include "library/constants.h"
#include "library/locals.h"
#include "library/util.h"
#include "library/app_builder.h"
#include "library/replace_visitor_with_tc.h"
#include "library/equations_compiler/util.h"
#include "library/equations_compiler/structural_rec.h"

namespace lean {
#define trace_struct(Code) lean_trace(name({"eqn_compiler", "structural_rec"}), scope_trace_env _scope1(m_ctx.env(), m_ctx); Code)

struct structural_rec_fn {
    type_context & m_ctx;
    structural_rec_fn(type_context & ctx):m_ctx(ctx) {}

    /** \brief Auxiliary object for checking whether recursive application are
        structurally smaller or not */
    struct check_rhs_fn {
        type_context & m_ctx;
        expr           m_lhs;
        expr           m_fn;
        expr           m_pattern;
        unsigned       m_arg_idx;

        check_rhs_fn(type_context & ctx, expr const & lhs, expr const & fn, expr const & pattern, unsigned arg_idx):
            m_ctx(ctx), m_lhs(lhs), m_fn(fn), m_pattern(pattern), m_arg_idx(arg_idx) {}

        bool is_constructor(expr const & e) const {
            return static_cast<bool>(eqns_env_interface(m_ctx).is_constructor(e));
        }

        /** \brief Return true iff \c s is structurally smaller than \c t OR equal to \c t */
        bool is_le(expr const & s, expr const & t) {
            return m_ctx.is_def_eq(s, t) || is_lt(s, t);
        }

        /** Return true iff \c s is structurally smaller than \c t */
        bool is_lt(expr s, expr t) {
            s = m_ctx.whnf(s);
            t = m_ctx.whnf(t);
            if (is_app(s)) {
                expr const & s_fn = get_app_fn(s);
                if (!is_constructor(s_fn))
                    return is_lt(s_fn, t); // f < t ==> s := f a_1 ... a_n < t
            }
            buffer<expr> t_args;
            expr const & t_fn = get_app_args(t, t_args);
            if (!is_constructor(t_fn))
                return false;
            return std::any_of(t_args.begin(), t_args.end(),
                               [&](expr const & t_arg) { return is_le(s, t_arg); });
        }

        /** \brief Return true iff all recursive applications in \c e are structurally smaller than \c m_pattern. */
        bool check_rhs(expr const & e) {
            switch (e.kind()) {
            case expr_kind::Var:   case expr_kind::Meta:
            case expr_kind::Local: case expr_kind::Constant:
            case expr_kind::Sort:
                return true;
            case expr_kind::Macro:
                for (unsigned i = 0; i < macro_num_args(e); i++)
                    if (!check_rhs(macro_arg(e, i)))
                        return false;
                return true;
            case expr_kind::App: {
                buffer<expr> args;
                expr const & fn = get_app_args(e, args);
                if (!check_rhs(fn))
                    return false;
                for (unsigned i = 0; i < args.size(); i++)
                    if (!check_rhs(args[i]))
                        return false;
                if (is_local(fn) && mlocal_name(fn) == mlocal_name(m_fn)) {
                    /* recusive application */
                    if (m_arg_idx < args.size()) {
                        expr const & arg = args[m_arg_idx];
                        /* arg must be structurally smaller than m_pattern */
                        if (!is_lt(arg, m_pattern)) {
                            trace_struct(tout() << "structural recursion on argument #" << (m_arg_idx+1) << " was not used "
                                         << "for '" << m_fn << "'\nargument #" << (m_arg_idx+1)
                                         << " in the application\n  "
                                         << e << "\nis not structurally smaller than the one occurring in "
                                         << "the equation left-hand-side\n  "
                                         << m_lhs << "\n";);
                            return false;
                        }
                    } else {
                        /* function is not fully applied */
                        trace_struct(tout() << "structural recursion on argument #" << (m_arg_idx+1) << " was not used "
                                     << "for '" << m_fn << "' because of the partial application\n  "
                                     << e << "\n";);
                        return false;
                    }
                }
                return true;
            }
            case expr_kind::Let:
                if (!check_rhs(let_value(e))) {
                    return false;
                } else {
                    type_context::tmp_locals locals(m_ctx);
                    return check_rhs(instantiate(let_body(e), locals.push_local_from_let(e)));
                }
            case expr_kind::Lambda:
            case expr_kind::Pi:
                if (!check_rhs(binding_domain(e))) {
                    return false;
                } else {
                    type_context::tmp_locals locals(m_ctx);
                    return check_rhs(instantiate(binding_body(e), locals.push_local_from_binding(e)));
                }
            }
            lean_unreachable();
        }

        bool operator()(expr const & e) {
            return check_rhs(e);
        }
    };

    bool check_rhs(expr const & lhs, expr const & fn, expr pattern, unsigned arg_idx, expr const & rhs) {
        pattern = m_ctx.whnf(pattern);
        return check_rhs_fn(m_ctx, lhs, fn, pattern, arg_idx)(rhs);
    }

    bool check_eq(expr const & eqn, unsigned arg_idx) {
        unpack_eqn ue(m_ctx, eqn);
        buffer<expr> args;
        expr const & fn  = get_app_args(ue.lhs(), args);
        return check_rhs(ue.lhs(), fn, args[arg_idx], arg_idx, ue.rhs());
    }

    static bool depends_on_locals(expr const & e, type_context::tmp_locals const & locals) {
        return depends_on_any(e, locals.as_buffer().size(), locals.as_buffer().data());
    }

    bool check_arg_type(unpack_eqns const & ues, unsigned arg_idx) {
        type_context::tmp_locals locals(m_ctx);
        /* We can only use structural recursion on arg_idx IF
           1- Type is an inductive datatype with support for the brec_on construction.
           2- Type parameters do not depend on other arguments of the function being defined. */
        expr fn      = ues.get_fn(0);
        expr fn_type = m_ctx.infer(fn);
        for (unsigned i = 0; i < arg_idx; i++) {
            fn_type = m_ctx.whnf(fn_type);
            if (!is_pi(fn_type)) throw_ill_formed_eqns();
            fn_type = instantiate(binding_body(fn_type), locals.push_local_from_binding(fn_type));
        }
        if (!is_pi(fn_type)) throw_ill_formed_eqns();
        expr arg_type = binding_domain(fn_type);
        buffer<expr> I_args;
        expr I        = get_app_args(arg_type, I_args);
        if (!eqns_env_interface(m_ctx).is_inductive(I)) {
            trace_struct(tout() << "structural recursion on argument #" << (arg_idx+1) << " was not used "
                         << "for '" << fn << "' because type is not inductive\n  "
                         << arg_type << "\n";);
            return false;
        }
        if (!m_ctx.env().find(name(const_name(I), "brec_on"))) {
            trace_struct(tout() << "structural recursion on argument #" << (arg_idx+1) << " was not used "
                         << "for '" << fn << "' because the inductive type '" << I << "' does have brec_on recursor\n  "
                         << arg_type << "\n";);
            return false;
        }
        unsigned nindices = eqns_env_interface(m_ctx).get_inductive_num_indices(const_name(I));
        if (nindices > 0) {
            trace_struct(tout() << "structural recursion on argument #" << (arg_idx+1) << " was not used "
                         << "for '" << fn << "' because the inductive type '" << I << "' is an indexed family\n  "
                         << arg_type << "\n";);
            return false;
        }
        if (depends_on_locals(arg_type, locals)) {
            trace_struct(tout() << "structural recursion on argument #" << (arg_idx+1) << " was not used "
                         << "for '" << fn << "' because type parameter depends on previous arguments\n  "
                         << arg_type << "\n";);
            return false;
        }
        return true;
    }

    optional<unsigned> find_rec_arg(unpack_eqns const & ues) {
        buffer<expr> const & eqns = ues.get_eqns_of(0);
        unsigned arity = ues.get_arity_of(0);
        for (unsigned i = 0; i < arity; i++) {
            if (check_arg_type(ues, i)) {
                bool ok = true;
                for (expr const & eqn : eqns) {
                    if (!check_eq(eqn, i)) {
                        ok = false;
                        break;
                    }
                }
                if (ok) return optional<unsigned>(i);
            }
        }
        return optional<unsigned>();
    }

    /* Return the type of the new function, and the type of the motive for below/brec_on */
    pair<expr, expr> mk_new_fn_motive_types(unpack_eqns const & ues, unsigned arg_idx) {
        type_context::tmp_locals locals(m_ctx);
        expr fn        = ues.get_fn(0);
        expr fn_type   = m_ctx.infer(fn);
        unsigned arity = ues.get_arity_of(0);
        expr rec_arg;
        buffer<expr> other_args;
        for (unsigned i = 0; i < arity; i++) {
            fn_type = m_ctx.whnf(fn_type);
            if (!is_pi(fn_type)) throw_ill_formed_eqns();
            expr arg = locals.push_local_from_binding(fn_type);
            if (i == arg_idx) {
                rec_arg = arg;
            } else {
                other_args.push_back(arg);
            }
            fn_type  = instantiate(binding_body(fn_type), arg);
        }
        buffer<expr> I_args;
        expr I = get_app_args(m_ctx.infer(rec_arg), I_args);
        expr  motive = m_ctx.mk_pi(other_args, fn_type);
        level u      = get_level(m_ctx, motive);
        motive       = m_ctx.mk_lambda(rec_arg, motive);
        lean_assert(is_constant(I));
        buffer<level> below_lvls;
        below_lvls.push_back(u);
        for (level const & v : const_levels(I))
            below_lvls.push_back(v);
        expr below       = mk_app(mk_constant(name(const_name(I), "below"), to_list(below_lvls)), I_args);
        expr motive_type = binding_domain(m_ctx.relaxed_whnf(m_ctx.infer(below)));
        below            = mk_app(below, motive, rec_arg);
        locals.push_local("_F", below);
        return mk_pair(locals.mk_pi(fn_type), motive_type);
    }

    struct elim_rec_apps_failed {};

    struct elim_rec_apps_fn : public replace_visitor_with_tc {
        expr           m_fn;
        unsigned       m_arg_idx;
        expr           m_F;
        expr           m_C;

        elim_rec_apps_fn(type_context & ctx, expr const & fn,
                         unsigned arg_idx, expr const & F, expr const & C):
            replace_visitor_with_tc(ctx),
            m_fn(fn), m_arg_idx(arg_idx), m_F(F), m_C(C) {}

        /** \brief Retrieve result for \c a from the below dictionary \c d. \c d is a term made of products,
            and m_C (the abstract local). */
        optional<expr> to_below(expr const & d, expr const & a, expr const & F) {
            expr const & fn = get_app_fn(d);
            if (is_constant(fn, get_prod_name())) {
                expr d_arg1 = m_ctx.whnf(app_arg(app_fn(d)));
                expr d_arg2 = m_ctx.whnf(app_arg(d));
                if (auto r = to_below(d_arg1, a, mk_pr1(m_ctx, F)))
                    return r;
                else if (auto r = to_below(d_arg2, a, mk_pr2(m_ctx, F)))
                    return r;
                else
                    return none_expr();
            } else if (is_local(fn)) {
                if (mlocal_name(m_C) == mlocal_name(fn) && m_ctx.is_def_eq(app_arg(d), a))
                    return some_expr(F);
                return none_expr();
            } else if (is_pi(d)) {
                if (is_app(a)) {
                    expr new_d = m_ctx.whnf(instantiate(binding_body(d), app_arg(a)));
                    return to_below(new_d, a, mk_app(F, app_arg(a)));
                } else {
                    return none_expr();
                }
            } else {
                return none_expr();
            }
        }

        expr elim(buffer<expr> const & args, tag g) {
            /* Replace motives with abstract one m_C.
               We use the abstract motive m_C as "marker". */
            buffer<expr> below_args;
            expr const & below_cnst = get_app_args(m_ctx.infer(m_F), below_args);
            below_args[below_args.size() - 2] = m_C;
            expr abst_below   = mk_app(below_cnst, below_args);
            expr below_dict   = m_ctx.whnf(abst_below);
            expr rec_arg      = m_ctx.whnf(args[m_arg_idx]);
            if (optional<expr> b = to_below(below_dict, rec_arg, m_F)) {
                expr r = *b;
                for (unsigned i = 0; i < args.size(); i++) {
                    if (i != m_arg_idx)
                        r = mk_app(r, args[i], g);
                }
                return r;
            } else {
                throw elim_rec_apps_failed();
            }
        }

        virtual expr visit_local(expr const & e) {
            if (mlocal_name(e) == mlocal_name(m_fn)) {
                /* unexpected occurrence of recursive function */
                throw elim_rec_apps_failed();
            }
            return e;
        }

        virtual expr visit_app(expr const & e) {
            expr const & fn = get_app_fn(e);
            if (is_local(fn) && mlocal_name(fn) == mlocal_name(m_fn)) {
                buffer<expr> args;
                get_app_args(e, args);
                if (m_arg_idx >= args.size()) throw elim_rec_apps_failed();
                buffer<expr> new_args;
                for (expr const & arg : args)
                    new_args.push_back(visit(arg));
                return elim(new_args, e.get_tag());
            } else {
                return replace_visitor_with_tc::visit_app(e);
            }
        }
    };

    void update_eqs(unpack_eqns & ues, expr const & fn, expr const & new_fn, unsigned arg_idx, expr const & motive_type) {
        /* C is a temporary "abstract" motive, we use it to access the "brec_on dictionary".
           The "brec_on dictionary is an element of type below, and it is the last argument of the new function. */
        expr C = mk_local(mk_fresh_name(), "_C", motive_type, binder_info());
        buffer<expr> & eqns = ues.get_eqns_of(0);
        for (expr & eqn : eqns) {
            unpack_eqn ue(m_ctx, eqn);
            expr lhs = ue.lhs();
            expr rhs = ue.rhs();
            buffer<expr> lhs_args;
            get_app_args(lhs, lhs_args);
            expr new_lhs = mk_app(new_fn, lhs_args);
            expr type    = m_ctx.whnf(m_ctx.infer(new_lhs));
            lean_assert(is_pi(type));
            expr F       = ue.add_var(binding_name(type), binding_domain(type));
            new_lhs      = mk_app(new_lhs, F);
            ue.lhs()     = new_lhs;
            ue.rhs()     = elim_rec_apps_fn(m_ctx, fn, arg_idx, F, C)(rhs);
            eqn          = ue.repack();
        }
    }

    optional<expr> operator()(expr const & e, unsigned & arg_idx) {
        unpack_eqns ues(m_ctx, e);
        if (ues.get_num_fns() != 1) {
            trace_struct(tout() << "structural recursion is not supported for mutually recursive functions:";
                         for (unsigned i = 0; i < ues.get_num_fns(); i++)
                             tout() << " " << ues.get_fn(i);
                         tout() << "\n";);
            return none_expr();
        }
        optional<unsigned> r = find_rec_arg(ues);
        if (!r) return none_expr();
        arg_idx = *r;
        expr fn = ues.get_fn(0);
        trace_struct(tout() << "using structural recursion on argument #" << (arg_idx+1) <<
                     " for '" << fn << "'\n";);
        expr new_fn_type, motive_type;
        std::tie(new_fn_type, motive_type) = mk_new_fn_motive_types(ues, arg_idx);
        trace_struct(
            tout() << "\n";
            tout() << "new function type: " << new_fn_type << "\n";
            tout() << "motive type:       " << motive_type << "\n";);
        expr new_fn = ues.update_fn_type(0, new_fn_type);
        try {
            update_eqs(ues, fn, new_fn, arg_idx, motive_type);
        } catch (elim_rec_apps_failed &) {
            trace_struct(tout() << "failed to compile equations/match using structural recursion, "
                         << "when creating new set of equations\n";);
            return none_expr();
        }
        expr new_eqns = ues.repack();
        trace_struct(tout() << "result:\n" << new_eqns << "\n";);
        return some_expr(new_eqns);
    }
};

optional<expr> try_structural_rec(type_context & ctx, expr const & e, unsigned & arg_idx) {
    return structural_rec_fn(ctx)(e, arg_idx);
}

void initialize_structural_rec() {
    register_trace_class({"eqn_compiler", "structural_rec"});
}
void finalize_structural_rec() {}
}
<|endoftext|>


<commit_before>#ifndef RECOMBINER_HPP_
#define RECOMBINER_HPP_

template < class Sequence, class Engine >
class recombiner {
public:
    template < class Generator >
    Sequence operator()( Sequence base, Sequence alt, Generator & gen, bool should_copy ) {
        assert( false );
    }
};

#include "clotho/powerset/variable_subset_recombination.hpp"

template < class E, class B, class BM, class EK, class C >
class recombiner< clotho::powersets::variable_subset< E, B, BM, EK >,
    clotho::recombine::recombination< clotho::powersets::variable_subset< E, B, BM, EK >, C > > {
public:
    typedef clotho::powersets::variable_subset< E, B, BM, EK >  sequence_type;
    typedef typename sequence_type::pointer                     sequence_pointer;

    typedef sequence_pointer                                    result_type;

    typedef C                                                   classifier_type;
    typedef typename C::param_type                              classifier_param;

    typedef clotho::recombine::recombination< clotho::powersets::variable_subset< E, B, BM, EK >, C > engine_type;

    recombiner( const engine_type & eng ) : m_engine( eng ) {}

    result_type operator()( std::pair< sequence_pointer, sequence_pointer > ind, bool should_copy ) {
        return operator()( ind.first, ind.second, should_copy );
    }

    result_type operator()( sequence_pointer base, sequence_pointer alt, bool should_copy ) {
        if( base == alt ) {
            if( !base ) {
                // both sequences must be NULL
                return sequence_pointer();
            } else if( should_copy ) {
                return base;
            }

            sequence_pointer res = base->clone();
            return res;
        }

        // at this point neiter base or alt can both be NULL
        typename sequence_type::powerset_type * p = ((base) ? base->getParent() : alt->getParent());
        assert( p );

        m_engine( base, alt );

        sequence_pointer res;
        if( !m_engine.isEmpty() ) {
            if( !should_copy ) {
                res = p->create_subset( *m_engine.getResultSequence() );
            } else if( m_engine.isMatchBase() ) {
                res = base;
            } else if( m_engine.isMatchAlt() ) {
                res = alt;
            } else {
                res = p->create_subset( *m_engine.getResultSequence() );
            }
        } else {
            res = p->create_subset();
        }

        return res;
    }

protected:
    engine_type   m_engine;
};

#include "recombination_generator.hpp"
#include "recombiner_generator.hpp"

#endif  // RECOMBINER_HPP_
<commit_msg>Added two tag template parameters; Formatting<commit_after>#ifndef RECOMBINER_HPP_
#define RECOMBINER_HPP_

template < class Sequence, class Engine >
class recombiner {
public:
    template < class Generator >
    Sequence operator()( Sequence base, Sequence alt, Generator & gen, bool should_copy ) {
        assert( false );
    }
};

#include "clotho/powerset/variable_subset_recombination.hpp"

template < class E, class B, class BM, class EK, class C, class T0, class T1 >
class recombiner< clotho::powersets::variable_subset< E, B, BM, EK >,
    clotho::recombine::recombination< clotho::powersets::variable_subset< E, B, BM, EK >, C, T0, T1 > > {
public:
    typedef clotho::powersets::variable_subset< E, B, BM, EK >  sequence_type;
    typedef typename sequence_type::pointer                     sequence_pointer;

    typedef sequence_pointer                                    result_type;

    typedef C                                                   classifier_type;
//    typedef typename C::param_type                              classifier_param;

    typedef clotho::recombine::recombination< clotho::powersets::variable_subset< E, B, BM, EK >, C, T0, T1 > engine_type;

    recombiner( const engine_type & eng ) : m_engine( eng ) {}

    result_type operator()( std::pair< sequence_pointer, sequence_pointer > ind, bool should_copy ) {
        return operator()( ind.first, ind.second, should_copy );
    }

    result_type operator()( sequence_pointer base, sequence_pointer alt, bool should_copy ) {
        if( base == alt ) {
            if( !base ) {
                // both sequences must be NULL
                return sequence_pointer();
            } else if( should_copy ) {
                return base;
            }

            sequence_pointer res = base->clone();
            return res;
        }

        // at this point neiter base or alt can both be NULL
        typename sequence_type::powerset_type * p = ((base) ? base->getParent() : alt->getParent());
        assert( p );

        m_engine( base, alt );

        sequence_pointer res;
        if( !m_engine.isEmpty() ) {
            if( !should_copy ) {
                res = p->create_subset( *m_engine.getResultSequence() );
            } else if( m_engine.isMatchBase() ) {
                res = base;
            } else if( m_engine.isMatchAlt() ) {
                res = alt;
            } else {
                res = p->create_subset( *m_engine.getResultSequence() );
            }
        } else {
            res = p->create_subset();
        }

        return res;
    }

protected:
    engine_type   m_engine;
};

#include "clotho/powerset/vector_subset_recombination.hpp"

template < class E, class B, class BM, class EK, class C, class T0, class T1 >
class recombiner< clotho::powersets::vector_subset< E, B, BM, EK >,
    clotho::recombine::recombination< clotho::powersets::vector_subset< E, B, BM, EK >, C, T0, T1 > > {
public:
    typedef clotho::powersets::vector_subset< E, B, BM, EK >  sequence_type;
    typedef typename sequence_type::pointer                     sequence_pointer;

    typedef sequence_pointer                                    result_type;

    typedef C                                                   classifier_type;

    typedef clotho::recombine::recombination< clotho::powersets::vector_subset< E, B, BM, EK >, C, T0, T1 > engine_type;

    recombiner( const engine_type & eng ) : m_engine( eng ) {}

    result_type operator()( std::pair< sequence_pointer, sequence_pointer > ind, bool should_copy ) {
        return operator()( ind.first, ind.second, should_copy );
    }

    result_type operator()( sequence_pointer base, sequence_pointer alt, bool should_copy ) {
        if( base == alt ) {
            if( !base ) {
                // both sequences must be NULL
                return sequence_pointer();
            } else if( should_copy ) {
                return base;
            }

            sequence_pointer res = base->clone();
            return res;
        }

        // at this point neiter base or alt can both be NULL
        typename sequence_type::powerset_type * p = ((base) ? base->getParent() : alt->getParent());
        assert( p );

        m_engine( base, alt );

        sequence_pointer res;
        if( !m_engine.isEmpty() ) {
            if( !should_copy ) {
                res = p->create_subset( *m_engine.getResultSequence() );
            } else if( m_engine.isMatchBase() ) {
                res = base;
            } else if( m_engine.isMatchAlt() ) {
                res = alt;
            } else {
                res = p->create_subset( *m_engine.getResultSequence() );
            }
        } else {
            res = p->create_subset();
        }

        return res;
    }

protected:
    engine_type   m_engine;
};

#include "recombination_generator.hpp"
#include "recombiner_generator.hpp"

#endif  // RECOMBINER_HPP_
<|endoftext|>


<commit_before>//
// (c) Copyright 2017 DESY,ESS
//
// This file is part of h5pp.
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
// Boston, MA  02110-1301 USA
// ===========================================================================
//
// Authors:
//    Eugen Wintersberger <eugen.wintersberger@desy.de>
//    Martin Shetty <martin.shetty@esss.se>
// Created on: Oct 19, 2017
//

#include <gtest/gtest.h>
#include <h5cpp/datatype/datatype.hpp>

using namespace hdf5;
using namespace hdf5::datatype;

TEST(Datatype, Constructors)
{
  Datatype a(ObjectHandle(H5Tcopy(H5T_NATIVE_INT)));
  EXPECT_TRUE(a.get_class()==Class::INTEGER);

  auto b = Datatype(ObjectHandle(H5Tcopy(H5T_NATIVE_INT)));
  EXPECT_TRUE(b.get_class()==Class::INTEGER);

  Datatype c = b;
  EXPECT_TRUE(c.get_class()==Class::INTEGER);

  Datatype d(b);
  EXPECT_TRUE(d.get_class()==Class::INTEGER);
}

<commit_msg>better tests for Datatype constructors and assignment #1<commit_after>//
// (c) Copyright 2017 DESY,ESS
//
// This file is part of h5pp.
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
// Boston, MA  02110-1301 USA
// ===========================================================================
//
// Authors:
//    Eugen Wintersberger <eugen.wintersberger@desy.de>
//    Martin Shetty <martin.shetty@esss.se>
// Created on: Oct 19, 2017
//

#include <gtest/gtest.h>
#include <h5cpp/datatype/datatype.hpp>

using namespace hdf5;
using namespace hdf5::datatype;

TEST(Datatype, Constructors)
{
  Datatype a(ObjectHandle(H5Tcopy(H5T_NATIVE_INT)));
  EXPECT_TRUE(a.get_class()==Class::INTEGER);

  auto b = Datatype(ObjectHandle(H5Tcopy(H5T_NATIVE_INT)));
  EXPECT_TRUE(b.get_class()==Class::INTEGER);

  Datatype c = b = a;
  EXPECT_TRUE(c.get_class()==Class::INTEGER);
  EXPECT_NE(static_cast<hid_t>(a), static_cast<hid_t>(b));
  EXPECT_NE(static_cast<hid_t>(b), static_cast<hid_t>(c));
  EXPECT_NE(static_cast<hid_t>(a), static_cast<hid_t>(c));

  Datatype d(b);
  EXPECT_TRUE(d.get_class()==Class::INTEGER);
  EXPECT_NE(static_cast<hid_t>(d), static_cast<hid_t>(b));
}

<|endoftext|>


<commit_before>#ifndef BLOCK_MASKS_HPP_
#define BLOCK_MASKS_HPP_

namespace clotho {
namespace utility {

/**
 * Block masks
 *
 * Object with lookup tables for common masks used in bit-based algorithms.
 *
 */
template < class Block, unsigned int N = (sizeof( Block ) * 8) >
class block_masks  {
public:
    static const unsigned int bits_per_block = N;

    typedef Block block_type;
    typedef Block mask_type;

    ///  LOW_BIT_MASK => bits_{[0, n]} = 1
    static const mask_type low_order_bit_masks[ bits_per_block ];

    /// OFFSET_BIT_MASK => bit_[n] = 1
    static const mask_type bit_position_masks[ bits_per_block ];

    static mask_type low_order_mask( unsigned int idx ) {
        return (( 1 << (idx + 1) ) - 1);
    }

    static mask_type position_mask( unsigned int idx ) {
        return (1 << idx);
    }
};

/// OFFSET_BIT_MASK => bit_[n] = 1
#define OFFSET_BIT_MASK( n ) (1UL << n)

///  LOW_BIT_MASK => bits_{[0, n]} = 1
#define LOW_BIT_MASK( n ) ((1UL << (n + 1) ) - 1)

#define SPEC64 block_masks< Block, 64 >
#define SPEC32 block_masks< Block, 32 >
#define SPEC16 block_masks< Block, 16 >
#define SPEC8 block_masks< Block, 8 >

template < class Block >
const typename SPEC64::mask_type  SPEC64::low_order_bit_masks[ SPEC64::bits_per_block ] = {
     LOW_BIT_MASK( 0 ), LOW_BIT_MASK( 1 ), LOW_BIT_MASK( 2 ), LOW_BIT_MASK( 3 ),
     LOW_BIT_MASK( 4 ), LOW_BIT_MASK( 5 ), LOW_BIT_MASK( 6 ), LOW_BIT_MASK( 7 ),
     LOW_BIT_MASK( 8 ), LOW_BIT_MASK( 9 ), LOW_BIT_MASK( 10 ), LOW_BIT_MASK( 11 ),
     LOW_BIT_MASK( 12 ), LOW_BIT_MASK( 13 ), LOW_BIT_MASK( 14 ), LOW_BIT_MASK( 15 ),
     LOW_BIT_MASK( 16 ), LOW_BIT_MASK( 17 ), LOW_BIT_MASK( 18 ), LOW_BIT_MASK( 19 ),
     LOW_BIT_MASK( 20 ), LOW_BIT_MASK( 21 ), LOW_BIT_MASK( 22 ), LOW_BIT_MASK( 23 ),
     LOW_BIT_MASK( 24 ), LOW_BIT_MASK( 25 ), LOW_BIT_MASK( 26 ), LOW_BIT_MASK( 27 ),
     LOW_BIT_MASK( 28 ), LOW_BIT_MASK( 29 ), LOW_BIT_MASK( 30 ), LOW_BIT_MASK( 31 ),
     LOW_BIT_MASK( 32 ), LOW_BIT_MASK( 33 ), LOW_BIT_MASK( 34 ), LOW_BIT_MASK( 35 ),
     LOW_BIT_MASK( 36 ), LOW_BIT_MASK( 37 ), LOW_BIT_MASK( 38 ), LOW_BIT_MASK( 39 ),
     LOW_BIT_MASK( 40 ), LOW_BIT_MASK( 41 ), LOW_BIT_MASK( 42 ), LOW_BIT_MASK( 43 ),
     LOW_BIT_MASK( 44 ), LOW_BIT_MASK( 45 ), LOW_BIT_MASK( 46 ), LOW_BIT_MASK( 47 ),
     LOW_BIT_MASK( 48 ), LOW_BIT_MASK( 49 ), LOW_BIT_MASK( 50 ), LOW_BIT_MASK( 51 ),
     LOW_BIT_MASK( 52 ), LOW_BIT_MASK( 53 ), LOW_BIT_MASK( 54 ), LOW_BIT_MASK( 55 ),
     LOW_BIT_MASK( 56 ), LOW_BIT_MASK( 57 ), LOW_BIT_MASK( 58 ), LOW_BIT_MASK( 59 ),
     LOW_BIT_MASK( 60 ), LOW_BIT_MASK( 61 ), LOW_BIT_MASK( 62 ), 0xFFFFFFFFFFFFFFFF
};

template < class Block >
const typename SPEC64::mask_type  SPEC64::bit_position_masks[ SPEC64::bits_per_block ] = {
    OFFSET_BIT_MASK( 0 ), OFFSET_BIT_MASK( 1 ), OFFSET_BIT_MASK( 2 ), OFFSET_BIT_MASK( 3 ),
    OFFSET_BIT_MASK( 4 ), OFFSET_BIT_MASK( 5 ), OFFSET_BIT_MASK( 6 ), OFFSET_BIT_MASK( 7 ),
    OFFSET_BIT_MASK( 8 ), OFFSET_BIT_MASK( 9 ), OFFSET_BIT_MASK( 10 ), OFFSET_BIT_MASK( 11 ),
    OFFSET_BIT_MASK( 12 ), OFFSET_BIT_MASK( 13 ), OFFSET_BIT_MASK( 14 ), OFFSET_BIT_MASK( 15 ),
    OFFSET_BIT_MASK( 16 ), OFFSET_BIT_MASK( 17 ), OFFSET_BIT_MASK( 18 ), OFFSET_BIT_MASK( 19 ),
    OFFSET_BIT_MASK( 20 ), OFFSET_BIT_MASK( 21 ), OFFSET_BIT_MASK( 22 ), OFFSET_BIT_MASK( 23 ),
    OFFSET_BIT_MASK( 24 ), OFFSET_BIT_MASK( 25 ), OFFSET_BIT_MASK( 26 ), OFFSET_BIT_MASK( 27 ),
    OFFSET_BIT_MASK( 28 ), OFFSET_BIT_MASK( 29 ), OFFSET_BIT_MASK( 30 ), OFFSET_BIT_MASK( 31 ),
    OFFSET_BIT_MASK( 32 ), OFFSET_BIT_MASK( 33 ), OFFSET_BIT_MASK( 34 ), OFFSET_BIT_MASK( 35 ),
    OFFSET_BIT_MASK( 36 ), OFFSET_BIT_MASK( 37 ), OFFSET_BIT_MASK( 38 ), OFFSET_BIT_MASK( 39 ),
    OFFSET_BIT_MASK( 40 ), OFFSET_BIT_MASK( 41 ), OFFSET_BIT_MASK( 42 ), OFFSET_BIT_MASK( 43 ),
    OFFSET_BIT_MASK( 44 ), OFFSET_BIT_MASK( 45 ), OFFSET_BIT_MASK( 46 ), OFFSET_BIT_MASK( 47 ),
    OFFSET_BIT_MASK( 48 ), OFFSET_BIT_MASK( 49 ), OFFSET_BIT_MASK( 50 ), OFFSET_BIT_MASK( 51 ),
    OFFSET_BIT_MASK( 52 ), OFFSET_BIT_MASK( 53 ), OFFSET_BIT_MASK( 54 ), OFFSET_BIT_MASK( 55 ),
    OFFSET_BIT_MASK( 56 ), OFFSET_BIT_MASK( 57 ), OFFSET_BIT_MASK( 58 ), OFFSET_BIT_MASK( 59 ),
    OFFSET_BIT_MASK( 60 ), OFFSET_BIT_MASK( 61 ), OFFSET_BIT_MASK( 62 ), OFFSET_BIT_MASK( 63 )
};

template < class Block >
const typename SPEC32::mask_type  SPEC32::low_order_bit_masks[ SPEC32::bits_per_block ] = {
     LOW_BIT_MASK( 0 ), LOW_BIT_MASK( 1 ), LOW_BIT_MASK( 2 ), LOW_BIT_MASK( 3 ),
     LOW_BIT_MASK( 4 ), LOW_BIT_MASK( 5 ), LOW_BIT_MASK( 6 ), LOW_BIT_MASK( 7 ),
     LOW_BIT_MASK( 8 ), LOW_BIT_MASK( 9 ), LOW_BIT_MASK( 10 ), LOW_BIT_MASK( 11 ),
     LOW_BIT_MASK( 12 ), LOW_BIT_MASK( 13 ), LOW_BIT_MASK( 14 ), LOW_BIT_MASK( 15 ),
     LOW_BIT_MASK( 16 ), LOW_BIT_MASK( 17 ), LOW_BIT_MASK( 18 ), LOW_BIT_MASK( 19 ),
     LOW_BIT_MASK( 20 ), LOW_BIT_MASK( 21 ), LOW_BIT_MASK( 22 ), LOW_BIT_MASK( 23 ),
     LOW_BIT_MASK( 24 ), LOW_BIT_MASK( 25 ), LOW_BIT_MASK( 26 ), LOW_BIT_MASK( 27 ),
     LOW_BIT_MASK( 28 ), LOW_BIT_MASK( 29 ), LOW_BIT_MASK( 30 ), 0xFFFFFFFF
};

template < class Block >
const typename SPEC32::mask_type  SPEC32::bit_position_masks[ SPEC32::bits_per_block ] = {
    OFFSET_BIT_MASK( 0 ), OFFSET_BIT_MASK( 1 ), OFFSET_BIT_MASK( 2 ), OFFSET_BIT_MASK( 3 ),
    OFFSET_BIT_MASK( 4 ), OFFSET_BIT_MASK( 5 ), OFFSET_BIT_MASK( 6 ), OFFSET_BIT_MASK( 7 ),
    OFFSET_BIT_MASK( 8 ), OFFSET_BIT_MASK( 9 ), OFFSET_BIT_MASK( 10 ), OFFSET_BIT_MASK( 11 ),
    OFFSET_BIT_MASK( 12 ), OFFSET_BIT_MASK( 13 ), OFFSET_BIT_MASK( 14 ), OFFSET_BIT_MASK( 15 ),
    OFFSET_BIT_MASK( 16 ), OFFSET_BIT_MASK( 17 ), OFFSET_BIT_MASK( 18 ), OFFSET_BIT_MASK( 19 ),
    OFFSET_BIT_MASK( 20 ), OFFSET_BIT_MASK( 21 ), OFFSET_BIT_MASK( 22 ), OFFSET_BIT_MASK( 23 ),
    OFFSET_BIT_MASK( 24 ), OFFSET_BIT_MASK( 25 ), OFFSET_BIT_MASK( 26 ), OFFSET_BIT_MASK( 27 ),
    OFFSET_BIT_MASK( 28 ), OFFSET_BIT_MASK( 29 ), OFFSET_BIT_MASK( 30 ), OFFSET_BIT_MASK( 31 )
};

template < class Block >
const typename SPEC16::mask_type  SPEC16::low_order_bit_masks[ SPEC16::bits_per_block ] = {
     LOW_BIT_MASK( 0 ), LOW_BIT_MASK( 1 ), LOW_BIT_MASK( 2 ), LOW_BIT_MASK( 3 ),
     LOW_BIT_MASK( 4 ), LOW_BIT_MASK( 5 ), LOW_BIT_MASK( 6 ), LOW_BIT_MASK( 7 ),
     LOW_BIT_MASK( 8 ), LOW_BIT_MASK( 9 ), LOW_BIT_MASK( 10 ), LOW_BIT_MASK( 11 ),
     LOW_BIT_MASK( 12 ), LOW_BIT_MASK( 13 ), LOW_BIT_MASK( 14 ), 0xFFFF
};

template < class Block >
const typename SPEC16::mask_type  SPEC16::bit_position_masks[ SPEC16::bits_per_block ] = {
    OFFSET_BIT_MASK( 0 ), OFFSET_BIT_MASK( 1 ), OFFSET_BIT_MASK( 2 ), OFFSET_BIT_MASK( 3 ),
    OFFSET_BIT_MASK( 4 ), OFFSET_BIT_MASK( 5 ), OFFSET_BIT_MASK( 6 ), OFFSET_BIT_MASK( 7 ),
    OFFSET_BIT_MASK( 8 ), OFFSET_BIT_MASK( 9 ), OFFSET_BIT_MASK( 10 ), OFFSET_BIT_MASK( 11 ),
    OFFSET_BIT_MASK( 12 ), OFFSET_BIT_MASK( 13 ), OFFSET_BIT_MASK( 14 ), OFFSET_BIT_MASK( 15 )
};

template < class Block >
const typename SPEC8::mask_type  SPEC8::low_order_bit_masks[ SPEC8::bits_per_block ] = {
     LOW_BIT_MASK( 0 ), LOW_BIT_MASK( 1 ), LOW_BIT_MASK( 2 ), LOW_BIT_MASK( 3 ),
     LOW_BIT_MASK( 4 ), LOW_BIT_MASK( 5 ), LOW_BIT_MASK( 6 ), 0xFF
};

template < class Block >
const typename SPEC8::mask_type  SPEC8::bit_position_masks[ SPEC8::bits_per_block ] = {
    OFFSET_BIT_MASK( 0 ), OFFSET_BIT_MASK( 1 ), OFFSET_BIT_MASK( 2 ), OFFSET_BIT_MASK( 3 ),
    OFFSET_BIT_MASK( 4 ), OFFSET_BIT_MASK( 5 ), OFFSET_BIT_MASK( 6 ), OFFSET_BIT_MASK( 7 )
};

#undef SPEC64
#undef SPEC32
#undef SPEC16
#undef SPEC8

}    namespace utility
}    namespace clotho

#endif  // BLOCK_MASKS_HPP_
<commit_msg>No longer necessary<commit_after><|endoftext|>


<commit_before>#pragma once

namespace  {

inline unsigned short bswap_16(unsigned short x) {
    return (x >> 8) | (x << 8);
}

inline unsigned int bswap_32(unsigned int x) {
    return (bswap_16(x & 0xffff) << 16) | (bswap_16(x >> 16));
}

inline unsigned long long bswap_64(unsigned long long x) {
    return (((unsigned long long) bswap_32(x & 0xffffffffull)) << 32) | (bswap_32(x >> 32));
}

}  // namespace
<commit_msg>Fix warning - removing unused function<commit_after>#pragma once

namespace  {

inline unsigned short bswap_16(unsigned short x) {
    return (x >> 8) | (x << 8);
}

inline unsigned int bswap_32(unsigned int x) {
    return (bswap_16(x & 0xffff) << 16) | (bswap_16(x >> 16));
}

}  // namespace
<|endoftext|>


<commit_before>// @(#)root/cont:$Id$
// Author: Fons Rademakers   13/08/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Collection abstract base class. This class describes the base        //
// protocol all collection classes have to implement. The ROOT          //
// collection classes always store pointers to objects that inherit     //
// from TObject. They never adopt the objects. Therefore, it is the     //
// user's responsability to take care of deleting the actual objects    //
// once they are not needed anymore. In exceptional cases, when the     //
// user is 100% sure nothing else is referencing the objects in the     //
// collection, one can delete all objects and the collection at the     //
// same time using the Delete() function.                               //
//                                                                      //
// Collections can be iterated using an iterator object (see            //
// TIterator). Depending on the concrete collection class there may be  //
// some additional methods of iterating. See the repective classes.     //
//                                                                      //
// TCollection inherits from TObject since we want to be able to have   //
// collections of collections.                                          //
//                                                                      //
// In a later release the collections may become templatized.           //
//                                                                      //
//Begin_Html
/*

*/
//End_Html
//////////////////////////////////////////////////////////////////////////

#include "TCollection.h"
#include "Varargs.h"
#include "TClass.h"
#include "TROOT.h"
#include "TBrowser.h"
#include "TObjectTable.h"
#include "TRegexp.h"
#include "TVirtualMutex.h"

TVirtualMutex *gCollectionMutex = 0;

TCollection   *TCollection::fgCurrentCollection = 0;
TObjectTable  *TCollection::fgGarbageCollection = 0;
Bool_t         TCollection::fgEmptyingGarbage   = kFALSE;
Int_t          TCollection::fgGarbageStack      = 0;

ClassImp(TCollection)
ClassImp(TIter)

//______________________________________________________________________________
void TCollection::AddAll(const TCollection *col)
{
   // Add all objects from collection col to this collection.

   TIter next(col);
   TObject *obj;

   while ((obj = next()))
      Add(obj);
}

//______________________________________________________________________________
void TCollection::AddVector(TObject *va_(obj1), ...)
{
   // Add all arguments to the collection. The list of objects must be
   // temrinated by 0, e.g.: l.AddVector(o1, o2, o3, o4, 0);

   va_list ap;
   va_start(ap, va_(obj1));
   TObject *obj;

   Add(va_(obj1));
   while ((obj = va_arg(ap, TObject *)))
      Add(obj);
   va_end(ap);
}

//______________________________________________________________________________
Bool_t TCollection::AssertClass(TClass *cl) const
{
   // Make sure all objects in this collection inherit from class cl.

   TObject *obj;
   TIter    next(this);
   Bool_t   error = kFALSE;

   if (!cl) {
      Error("AssertClass", "class == 0");
      return kTRUE;
   }

   for (int i = 0; (obj = next()); i++)
      if (!obj->InheritsFrom(cl)) {
         Error("AssertClass", "element %d is not an instance of class %s (%s)",
               i, cl->GetName(), obj->ClassName());
         error = kTRUE;
      }
   return error;
}

//______________________________________________________________________________
void TCollection::Browse(TBrowser *b)
{
   // Browse this collection (called by TBrowser).
   // If b=0, there is no Browse call TObject::Browse(0) instead.
   //         This means TObject::Inspect() will be invoked indirectly

   TIter next(this);
   TObject *obj;

   if (b)
      while ((obj = next())) b->Add(obj);
   else
      TObject::Browse(b);
}

//______________________________________________________________________________
Int_t TCollection::Compare(const TObject *obj) const
{
   // Compare two TCollection objects. Returns 0 when equal, -1 when this is
   // smaller and +1 when bigger (like strcmp()).

   if (this == obj) return 0;
   return fName.CompareTo(obj->GetName());
}

//______________________________________________________________________________
void TCollection::Draw(Option_t *option)
{
   // Draw all objects in this collection.
   // wildcarding supported, eg option="xxx*" draws only objects
   // with names xxx*

   TRegexp re(option,kTRUE);
   TIter next(this);
   TObject *object;
   Int_t nch = (option ? strlen(option) : 0);

   while ((object = next())) {
      TString s = object->GetName();
      if (nch && strcmp(option,object->GetName()) && s.Index(re) == kNPOS) continue;
      object->Draw(option);
   }
}

//______________________________________________________________________________
void TCollection::Dump() const
{
   // Dump all objects in this collection.

   TIter next(this);
   TObject *object;

   while ((object = next())) {
      object->Dump();
   }
}

//______________________________________________________________________________
TObject *TCollection::FindObject(const char *name) const
{
   // Find an object in this collection using its name. Requires a sequential
   // scan till the object has been found. Returns 0 if object with specified
   // name is not found.

   TIter next(this);
   TObject *obj;

   while ((obj = next()))
      if (!strcmp(name, obj->GetName())) return obj;
   return 0;
}

//______________________________________________________________________________
TObject *TCollection::operator()(const char *name) const
{
  // Find an object in this collection by name.

   return FindObject(name);
}

//______________________________________________________________________________
TObject *TCollection::FindObject(const TObject *obj) const
{
   // Find an object in this collection using the object's IsEqual()
   // member function. Requires a sequential scan till the object has
   // been found. Returns 0 if object is not found.
   // Typically this function is overridden by a more efficient version
   // in concrete collection classes (e.g. THashTable).

   TIter next(this);
   TObject *ob;

   while ((ob = next()))
      if (ob->IsEqual(obj)) return ob;
   return 0;
}

//______________________________________________________________________________
const char *TCollection::GetName() const
{
  // Return name of this collection.
  // if no name, return the collection class name.

   if (fName.Length() > 0) return fName.Data();
   return ClassName();
}

//______________________________________________________________________________
Int_t TCollection::GrowBy(Int_t delta) const
{
  // Increase the collection's capacity by delta slots.

   if (delta < 0) {
      Error("GrowBy", "delta < 0");
      delta = Capacity();
   }
   return Capacity() + TMath::Range(2, kMaxInt - Capacity(), delta);
}

//______________________________________________________________________________
Bool_t  TCollection::IsArgNull(const char *where, const TObject *obj) const
{
   // Returns true if object is a null pointer.

   return obj ? kFALSE : (Error(where, "argument is a null pointer"), kTRUE);
}

//______________________________________________________________________________
void TCollection::ls(Option_t *option) const
{
   // List (ls) all objects in this collection.
   // Wildcarding supported, eg option="xxx*" lists only objects
   // with names xxx*.

   TObject::ls(option);

   TRegexp re(option,kTRUE);
   TIter next(this);
   TObject *object;
   char *star = 0;
   if (option) star = (char*)strchr(option,'*');

   TROOT::IncreaseDirLevel();
   while ((object = next())) {
      if (star) {
         TString s = object->GetName();
         if (s != option && s.Index(re) == kNPOS) continue;
      }
      object->ls(option);
   }
   TROOT::DecreaseDirLevel();
}

//______________________________________________________________________________
void TCollection::Paint(Option_t *option)
{
   // Paint all objects in this collection.

   this->R__FOR_EACH(TObject,Paint)(option);
}

//______________________________________________________________________________
void TCollection::Print(Option_t *wildcard) const
{
   // Print all objects in this collection.
   // Wildcarding is supported, e.g. wildcard="xxx*" prints only objects
   // with names matching xxx*.

   TObject::Print(wildcard);

   if (!wildcard) wildcard = "";
   TRegexp re(wildcard, kTRUE);
   Int_t nch = strlen(wildcard);
   TIter next(this);
   TObject *object;

   while ((object = next())) {
      TString s = object->GetName();
      if (nch && s != wildcard && s.Index(re) == kNPOS) continue;
      object->Print(wildcard);
   }
}

//______________________________________________________________________________
void TCollection::Print(Option_t *wildcard, Option_t *option) const
{
   // Print all objects in this collection, passing option to the
   // objects Print() method.
   // Wildcarding is supported, e.g. wildcard="xxx*" prints only objects
   // with names matching xxx*.

   if (!wildcard) wildcard = "";
   TRegexp re(wildcard, kTRUE);
   Int_t nch = strlen(wildcard);
   TIter next(this);
   TObject *object;

   while ((object = next())) {
      TString s = object->GetName();
      if (nch && s != wildcard && s.Index(re) == kNPOS) continue;
      object->Print(option);
   }
}

//______________________________________________________________________________
void TCollection::RecursiveRemove(TObject *obj)
{
   // Remove object from this collection and recursively remove the object
   // from all other objects (and collections).

   if (!obj) return;

   // Scan list and remove obj in the list itself
   while (Remove(obj))
      ;

   // Scan again the list and invoke RecursiveRemove for all objects
   TIter next(this);
   TObject *object;

   while ((object = next())) {
      if (object->TestBit(kNotDeleted)) object->RecursiveRemove(obj);
   }
}

//______________________________________________________________________________
void TCollection::RemoveAll(TCollection *col)
{
   // Remove all objects in collection col from this collection.

   TIter next(col);
   TObject *obj;

   while ((obj = next()))
      Remove(obj);
}

//_______________________________________________________________________
void TCollection::Streamer(TBuffer &b)
{
   // Stream all objects in the collection to or from the I/O buffer.

   Int_t nobjects;
   TObject *obj;
   UInt_t R__s, R__c;

   if (b.IsReading()) {
      Version_t v = b.ReadVersion(&R__s, &R__c);
      if (v > 2)
         TObject::Streamer(b);
      if (v > 1)
         fName.Streamer(b);
      b >> nobjects;
      for (Int_t i = 0; i < nobjects; i++) {
         b >> obj;
         Add(obj);
      }
      b.CheckByteCount(R__s, R__c,TCollection::IsA());
   } else {
      R__c = b.WriteVersion(TCollection::IsA(), kTRUE);
      TObject::Streamer(b);
      fName.Streamer(b);
      nobjects = GetSize();
      b << nobjects;

      TIter next(this);

      while ((obj = next())) {
         b << obj;
      }
      b.SetByteCount(R__c, kTRUE);
   }
}

//______________________________________________________________________________
Int_t TCollection::Write(const char *name, Int_t option, Int_t bsize) const
{
   // Write all objects in this collection. By default all objects in
   // the collection are written individually (each object gets its
   // own key). Note, this is recursive, i.e. objects in collections
   // in the collection are also written individually. To write all
   // objects using a single key specify a name and set option to
   // TObject::kSingleKey (i.e. 1).

   if ((option & kSingleKey)) {
      return TObject::Write(name, option, bsize);
   } else {
      option &= ~kSingleKey;
      Int_t nbytes = 0;
      TIter next(this);
      TObject *obj;
      while ((obj = next())) {
         nbytes += obj->Write(name, option, bsize);
      }
      return nbytes;
   }
}

//______________________________________________________________________________
Int_t TCollection::Write(const char *name, Int_t option, Int_t bsize)
{
   // Write all objects in this collection. By default all objects in
   // the collection are written individually (each object gets its
   // own key). Note, this is recursive, i.e. objects in collections
   // in the collection are also written individually. To write all
   // objects using a single key specify a name and set option to
   // TObject::kSingleKey (i.e. 1).

   return ((const TCollection*)this)->Write(name,option,bsize);
}

// -------------------- Static data members access -----------------------------
//______________________________________________________________________________
TCollection *TCollection::GetCurrentCollection()
{
   // Return the globally accessible collection.

   return fgCurrentCollection;
}

//______________________________________________________________________________
void TCollection::SetCurrentCollection()
{
   // Set this collection to be the globally accesible collection.

   fgCurrentCollection = this;
}

//______________________________________________________________________________
void TCollection::StartGarbageCollection()
{
   // Set up for garbage collection.

   R__LOCKGUARD2(gCollectionMutex);
   if (!fgGarbageCollection) {
      fgGarbageCollection = new TObjectTable;
      fgEmptyingGarbage   = kFALSE;
      fgGarbageStack      = 0;
   }
   fgGarbageStack++;
}

//______________________________________________________________________________
void TCollection::EmptyGarbageCollection()
{
   // Do the garbage collection.

   R__LOCKGUARD2(gCollectionMutex);
   if (fgGarbageStack > 0) fgGarbageStack--;
   if (fgGarbageCollection && fgGarbageStack == 0 && fgEmptyingGarbage == kFALSE) {
      fgEmptyingGarbage = kTRUE;
      fgGarbageCollection->Delete();
      fgEmptyingGarbage = kFALSE;
      SafeDelete(fgGarbageCollection);
   }
}

//______________________________________________________________________________
void TCollection::GarbageCollect(TObject *obj)
{
   // Add to the list of things to be cleaned up.

   R__LOCKGUARD2(gCollectionMutex);
   if (fgGarbageCollection) {
      if (!fgEmptyingGarbage) {
         fgGarbageCollection->Add(obj);
      } else
         delete obj;
   } else
      delete obj;
}

//______________________________________________________________________________
void TCollection::SetOwner(Bool_t enable)
{
   // Set whether this collection is the owner (enable==true)
   // of its content.  If it is the owner of its contents,
   // these objects will be deleted whenever the collection itself
   // is delete.   The objects might also be deleted or destructed when Clear
   // is called (depending on the collection).

   if (enable)
      SetBit(kIsOwner);
   else
      ResetBit(kIsOwner);
}

//______________________________________________________________________________
TIter::TIter(const TIter &iter)
{
   // Copy a TIter. This involves allocating a new TIterator of the right
   // sub class and assigning it with the original.

   if (iter.fIterator) {
      fIterator = iter.GetCollection()->MakeIterator();
      fIterator->operator=(*iter.fIterator);
   } else
      fIterator = 0;
}

//______________________________________________________________________________
TIter &TIter::operator=(const TIter &rhs)
{
   // Assigning an TIter to another. This involves allocatiing a new TIterator
   // of the right sub class and assigning it with the original.

   if (this != &rhs) {
      if (rhs.fIterator) {
         delete fIterator;
         fIterator = rhs.GetCollection()->MakeIterator();
         fIterator->operator=(*rhs.fIterator);
      }
   }
   return *this;
}
<commit_msg>Witdraw changes from Matev in TCollection::ls. These chnges are nice improvements. However we have to renerate many roottest reference files to avoid roottest failing in many places.<commit_after>// @(#)root/cont:$Id$
// Author: Fons Rademakers   13/08/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Collection abstract base class. This class describes the base        //
// protocol all collection classes have to implement. The ROOT          //
// collection classes always store pointers to objects that inherit     //
// from TObject. They never adopt the objects. Therefore, it is the     //
// user's responsability to take care of deleting the actual objects    //
// once they are not needed anymore. In exceptional cases, when the     //
// user is 100% sure nothing else is referencing the objects in the     //
// collection, one can delete all objects and the collection at the     //
// same time using the Delete() function.                               //
//                                                                      //
// Collections can be iterated using an iterator object (see            //
// TIterator). Depending on the concrete collection class there may be  //
// some additional methods of iterating. See the repective classes.     //
//                                                                      //
// TCollection inherits from TObject since we want to be able to have   //
// collections of collections.                                          //
//                                                                      //
// In a later release the collections may become templatized.           //
//                                                                      //
//Begin_Html
/*

*/
//End_Html
//////////////////////////////////////////////////////////////////////////

#include "TCollection.h"
#include "Varargs.h"
#include "TClass.h"
#include "TROOT.h"
#include "TBrowser.h"
#include "TObjectTable.h"
#include "TRegexp.h"
#include "TVirtualMutex.h"

TVirtualMutex *gCollectionMutex = 0;

TCollection   *TCollection::fgCurrentCollection = 0;
TObjectTable  *TCollection::fgGarbageCollection = 0;
Bool_t         TCollection::fgEmptyingGarbage   = kFALSE;
Int_t          TCollection::fgGarbageStack      = 0;

ClassImp(TCollection)
ClassImp(TIter)

//______________________________________________________________________________
void TCollection::AddAll(const TCollection *col)
{
   // Add all objects from collection col to this collection.

   TIter next(col);
   TObject *obj;

   while ((obj = next()))
      Add(obj);
}

//______________________________________________________________________________
void TCollection::AddVector(TObject *va_(obj1), ...)
{
   // Add all arguments to the collection. The list of objects must be
   // temrinated by 0, e.g.: l.AddVector(o1, o2, o3, o4, 0);

   va_list ap;
   va_start(ap, va_(obj1));
   TObject *obj;

   Add(va_(obj1));
   while ((obj = va_arg(ap, TObject *)))
      Add(obj);
   va_end(ap);
}

//______________________________________________________________________________
Bool_t TCollection::AssertClass(TClass *cl) const
{
   // Make sure all objects in this collection inherit from class cl.

   TObject *obj;
   TIter    next(this);
   Bool_t   error = kFALSE;

   if (!cl) {
      Error("AssertClass", "class == 0");
      return kTRUE;
   }

   for (int i = 0; (obj = next()); i++)
      if (!obj->InheritsFrom(cl)) {
         Error("AssertClass", "element %d is not an instance of class %s (%s)",
               i, cl->GetName(), obj->ClassName());
         error = kTRUE;
      }
   return error;
}

//______________________________________________________________________________
void TCollection::Browse(TBrowser *b)
{
   // Browse this collection (called by TBrowser).
   // If b=0, there is no Browse call TObject::Browse(0) instead.
   //         This means TObject::Inspect() will be invoked indirectly

   TIter next(this);
   TObject *obj;

   if (b)
      while ((obj = next())) b->Add(obj);
   else
      TObject::Browse(b);
}

//______________________________________________________________________________
Int_t TCollection::Compare(const TObject *obj) const
{
   // Compare two TCollection objects. Returns 0 when equal, -1 when this is
   // smaller and +1 when bigger (like strcmp()).

   if (this == obj) return 0;
   return fName.CompareTo(obj->GetName());
}

//______________________________________________________________________________
void TCollection::Draw(Option_t *option)
{
   // Draw all objects in this collection.
   // wildcarding supported, eg option="xxx*" draws only objects
   // with names xxx*

   TRegexp re(option,kTRUE);
   TIter next(this);
   TObject *object;
   Int_t nch = (option ? strlen(option) : 0);

   while ((object = next())) {
      TString s = object->GetName();
      if (nch && strcmp(option,object->GetName()) && s.Index(re) == kNPOS) continue;
      object->Draw(option);
   }
}

//______________________________________________________________________________
void TCollection::Dump() const
{
   // Dump all objects in this collection.

   TIter next(this);
   TObject *object;

   while ((object = next())) {
      object->Dump();
   }
}

//______________________________________________________________________________
TObject *TCollection::FindObject(const char *name) const
{
   // Find an object in this collection using its name. Requires a sequential
   // scan till the object has been found. Returns 0 if object with specified
   // name is not found.

   TIter next(this);
   TObject *obj;

   while ((obj = next()))
      if (!strcmp(name, obj->GetName())) return obj;
   return 0;
}

//______________________________________________________________________________
TObject *TCollection::operator()(const char *name) const
{
  // Find an object in this collection by name.

   return FindObject(name);
}

//______________________________________________________________________________
TObject *TCollection::FindObject(const TObject *obj) const
{
   // Find an object in this collection using the object's IsEqual()
   // member function. Requires a sequential scan till the object has
   // been found. Returns 0 if object is not found.
   // Typically this function is overridden by a more efficient version
   // in concrete collection classes (e.g. THashTable).

   TIter next(this);
   TObject *ob;

   while ((ob = next()))
      if (ob->IsEqual(obj)) return ob;
   return 0;
}

//______________________________________________________________________________
const char *TCollection::GetName() const
{
  // Return name of this collection.
  // if no name, return the collection class name.

   if (fName.Length() > 0) return fName.Data();
   return ClassName();
}

//______________________________________________________________________________
Int_t TCollection::GrowBy(Int_t delta) const
{
  // Increase the collection's capacity by delta slots.

   if (delta < 0) {
      Error("GrowBy", "delta < 0");
      delta = Capacity();
   }
   return Capacity() + TMath::Range(2, kMaxInt - Capacity(), delta);
}

//______________________________________________________________________________
Bool_t  TCollection::IsArgNull(const char *where, const TObject *obj) const
{
   // Returns true if object is a null pointer.

   return obj ? kFALSE : (Error(where, "argument is a null pointer"), kTRUE);
}

//______________________________________________________________________________
void TCollection::ls(Option_t *option) const
{
   // List (ls) all objects in this collection.
   // Wildcarding supported, eg option="xxx*" lists only objects
   // with names xxx*.

   TRegexp re(option,kTRUE);
   TIter next(this);
   TObject *object;
   char *star = 0;
   if (option) star = (char*)strchr(option,'*');

   while ((object = next())) {
      if (star) {
         TString s = object->GetName();
         if (s != option && s.Index(re) == kNPOS) continue;
      }
      object->ls(option);
   }
}

//______________________________________________________________________________
void TCollection::Paint(Option_t *option)
{
   // Paint all objects in this collection.

   this->R__FOR_EACH(TObject,Paint)(option);
}

//______________________________________________________________________________
void TCollection::Print(Option_t *wildcard) const
{
   // Print all objects in this collection.
   // Wildcarding is supported, e.g. wildcard="xxx*" prints only objects
   // with names matching xxx*.

   if (!wildcard) wildcard = "";
   TRegexp re(wildcard, kTRUE);
   Int_t nch = strlen(wildcard);
   TIter next(this);
   TObject *object;

   while ((object = next())) {
      TString s = object->GetName();
      if (nch && s != wildcard && s.Index(re) == kNPOS) continue;
      object->Print();
   }
}

//______________________________________________________________________________
void TCollection::Print(Option_t *wildcard, Option_t *option) const
{
   // Print all objects in this collection, passing option to the
   // objects Print() method.
   // Wildcarding is supported, e.g. wildcard="xxx*" prints only objects
   // with names matching xxx*.

   if (!wildcard) wildcard = "";
   TRegexp re(wildcard, kTRUE);
   Int_t nch = strlen(wildcard);
   TIter next(this);
   TObject *object;

   while ((object = next())) {
      TString s = object->GetName();
      if (nch && s != wildcard && s.Index(re) == kNPOS) continue;
      object->Print(option);
   }
}

//______________________________________________________________________________
void TCollection::RecursiveRemove(TObject *obj)
{
   // Remove object from this collection and recursively remove the object
   // from all other objects (and collections).

   if (!obj) return;

   // Scan list and remove obj in the list itself
   while (Remove(obj))
      ;

   // Scan again the list and invoke RecursiveRemove for all objects
   TIter next(this);
   TObject *object;

   while ((object = next())) {
      if (object->TestBit(kNotDeleted)) object->RecursiveRemove(obj);
   }
}

//______________________________________________________________________________
void TCollection::RemoveAll(TCollection *col)
{
   // Remove all objects in collection col from this collection.

   TIter next(col);
   TObject *obj;

   while ((obj = next()))
      Remove(obj);
}

//_______________________________________________________________________
void TCollection::Streamer(TBuffer &b)
{
   // Stream all objects in the collection to or from the I/O buffer.

   Int_t nobjects;
   TObject *obj;
   UInt_t R__s, R__c;

   if (b.IsReading()) {
      Version_t v = b.ReadVersion(&R__s, &R__c);
      if (v > 2)
         TObject::Streamer(b);
      if (v > 1)
         fName.Streamer(b);
      b >> nobjects;
      for (Int_t i = 0; i < nobjects; i++) {
         b >> obj;
         Add(obj);
      }
      b.CheckByteCount(R__s, R__c,TCollection::IsA());
   } else {
      R__c = b.WriteVersion(TCollection::IsA(), kTRUE);
      TObject::Streamer(b);
      fName.Streamer(b);
      nobjects = GetSize();
      b << nobjects;

      TIter next(this);

      while ((obj = next())) {
         b << obj;
      }
      b.SetByteCount(R__c, kTRUE);
   }
}

//______________________________________________________________________________
Int_t TCollection::Write(const char *name, Int_t option, Int_t bsize) const
{
   // Write all objects in this collection. By default all objects in
   // the collection are written individually (each object gets its
   // own key). Note, this is recursive, i.e. objects in collections
   // in the collection are also written individually. To write all
   // objects using a single key specify a name and set option to
   // TObject::kSingleKey (i.e. 1).

   if ((option & kSingleKey)) {
      return TObject::Write(name, option, bsize);
   } else {
      option &= ~kSingleKey;
      Int_t nbytes = 0;
      TIter next(this);
      TObject *obj;
      while ((obj = next())) {
         nbytes += obj->Write(name, option, bsize);
      }
      return nbytes;
   }
}

//______________________________________________________________________________
Int_t TCollection::Write(const char *name, Int_t option, Int_t bsize)
{
   // Write all objects in this collection. By default all objects in
   // the collection are written individually (each object gets its
   // own key). Note, this is recursive, i.e. objects in collections
   // in the collection are also written individually. To write all
   // objects using a single key specify a name and set option to
   // TObject::kSingleKey (i.e. 1).

   return ((const TCollection*)this)->Write(name,option,bsize);
}

// -------------------- Static data members access -----------------------------
//______________________________________________________________________________
TCollection *TCollection::GetCurrentCollection()
{
   // Return the globally accessible collection.

   return fgCurrentCollection;
}

//______________________________________________________________________________
void TCollection::SetCurrentCollection()
{
   // Set this collection to be the globally accesible collection.

   fgCurrentCollection = this;
}

//______________________________________________________________________________
void TCollection::StartGarbageCollection()
{
   // Set up for garbage collection.

   R__LOCKGUARD2(gCollectionMutex);
   if (!fgGarbageCollection) {
      fgGarbageCollection = new TObjectTable;
      fgEmptyingGarbage   = kFALSE;
      fgGarbageStack      = 0;
   }
   fgGarbageStack++;
}

//______________________________________________________________________________
void TCollection::EmptyGarbageCollection()
{
   // Do the garbage collection.

   R__LOCKGUARD2(gCollectionMutex);
   if (fgGarbageStack > 0) fgGarbageStack--;
   if (fgGarbageCollection && fgGarbageStack == 0 && fgEmptyingGarbage == kFALSE) {
      fgEmptyingGarbage = kTRUE;
      fgGarbageCollection->Delete();
      fgEmptyingGarbage = kFALSE;
      SafeDelete(fgGarbageCollection);
   }
}

//______________________________________________________________________________
void TCollection::GarbageCollect(TObject *obj)
{
   // Add to the list of things to be cleaned up.

   R__LOCKGUARD2(gCollectionMutex);
   if (fgGarbageCollection) {
      if (!fgEmptyingGarbage) {
         fgGarbageCollection->Add(obj);
      } else
         delete obj;
   } else
      delete obj;
}

//______________________________________________________________________________
void TCollection::SetOwner(Bool_t enable)
{
   // Set whether this collection is the owner (enable==true)
   // of its content.  If it is the owner of its contents,
   // these objects will be deleted whenever the collection itself
   // is delete.   The objects might also be deleted or destructed when Clear
   // is called (depending on the collection).

   if (enable)
      SetBit(kIsOwner);
   else
      ResetBit(kIsOwner);
}

//______________________________________________________________________________
TIter::TIter(const TIter &iter)
{
   // Copy a TIter. This involves allocating a new TIterator of the right
   // sub class and assigning it with the original.

   if (iter.fIterator) {
      fIterator = iter.GetCollection()->MakeIterator();
      fIterator->operator=(*iter.fIterator);
   } else
      fIterator = 0;
}

//______________________________________________________________________________
TIter &TIter::operator=(const TIter &rhs)
{
   // Assigning an TIter to another. This involves allocatiing a new TIterator
   // of the right sub class and assigning it with the original.

   if (this != &rhs) {
      if (rhs.fIterator) {
         delete fIterator;
         fIterator = rhs.GetCollection()->MakeIterator();
         fIterator->operator=(*rhs.fIterator);
      }
   }
   return *this;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: ZipFile.hxx,v $
 *
 *  $Revision: 1.14 $
 *
 *  last change: $Author: mtg $ $Date: 2001-09-05 19:32:43 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Martin Gallwey (gallwey@sun.com)
 *
 *
 ************************************************************************/
#ifndef _ZIP_FILE_HXX
#define _ZIP_FILE_HXX

#ifndef _BYTE_GRABBER_HXX_
#include <ByteGrabber.hxx>
#endif
#ifndef _ENTRY_HASH_HXX
#include <EntryHash.hxx>
#endif
#ifndef _INFLATER_HXX
#include <Inflater.hxx>
#endif
#ifndef _COM_SUN_STAR_PACKAGES_ZIP_ZIPEXCEPTION_HPP_
#include <com/sun/star/packages/zip/ZipException.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_NOSUCHELEMENTEXCEPTION_HPP_
#include <com/sun/star/container/NoSuchElementException.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_WRAPPEDTARGETEXCEPTION_HPP_
#include <com/sun/star/lang/WrappedTargetException.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _VOS_REF_H_
#include <vos/ref.hxx>
#endif
/*
 * We impose arbitrary but reasonable limit on ZIP files.
 */

#define ZIP_MAXNAMELEN 512
#define ZIP_MAXEXTRA 256
#define ZIP_MAXENTRIES (0x10000 - 2)

typedef void* rtlCipher;
class ZipEnumeration;
class EncryptionData;

class ZipFile
{
protected:
    ::rtl::OUString sName;          /* zip file name */
    ::rtl::OUString sComment;       /* zip file comment */
    EntryHash       aEntries;
    ByteGrabber     aGrabber;
    Inflater        aInflater;
    com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xStream;
    com::sun::star::uno::Reference < com::sun::star::io::XSeekable > xSeek;
    const ::com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > xFactory;

    com::sun::star::uno::Reference < com::sun::star::io::XInputStream >  createMemoryStream(
            com::sun::star::packages::zip::ZipEntry & rEntry,
            const vos::ORef < EncryptionData > &rData,
            sal_Bool bRawStream );

    com::sun::star::uno::Reference < com::sun::star::io::XInputStream >  createFileStream(
            com::sun::star::packages::zip::ZipEntry & rEntry,
            const vos::ORef < EncryptionData > &rData,
            sal_Bool bRawStream );
public:
    ZipFile( com::sun::star::uno::Reference < com::sun::star::io::XInputStream > &xInput,
             const com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > &xNewFactory,
             sal_Bool bInitialise)
        throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException);

    ~ZipFile();

    void setInputStream ( com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xNewStream );
    sal_uInt32 SAL_CALL getHeader(const ::com::sun::star::packages::zip::ZipEntry& rEntry)
        throw(::com::sun::star::io::IOException, ::com::sun::star::packages::zip::ZipException, ::com::sun::star::uno::RuntimeException);
    ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getRawStream(
            ::com::sun::star::packages::zip::ZipEntry& rEntry,
            const vos::ORef < EncryptionData > &rData)
        throw(::com::sun::star::io::IOException, ::com::sun::star::packages::zip::ZipException, ::com::sun::star::uno::RuntimeException);

    static void StaticGetCipher ( const vos::ORef < EncryptionData > & xEncryptionData, rtlCipher &rCipher );

    // XElementAccess
    ::com::sun::star::uno::Type SAL_CALL getElementType(  )
        throw(::com::sun::star::uno::RuntimeException);
    sal_Bool SAL_CALL hasElements(  )
        throw(::com::sun::star::uno::RuntimeException);
    // XZipFile
    ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream(
            ::com::sun::star::packages::zip::ZipEntry& rEntry,
            const vos::ORef < EncryptionData > &rData)
        throw(::com::sun::star::io::IOException, ::com::sun::star::packages::zip::ZipException, ::com::sun::star::uno::RuntimeException);
    ::rtl::OUString SAL_CALL getName(  )
        throw(::com::sun::star::uno::RuntimeException);
    sal_Int32 SAL_CALL getSize(  )
        throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL close(  )
        throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

    // XNameAccess
    ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName )
        throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames(  )
        throw(::com::sun::star::uno::RuntimeException);
    sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName )
        throw(::com::sun::star::uno::RuntimeException);

    ZipEnumeration * SAL_CALL entries(  );
protected:
    sal_Bool        readLOC (com::sun::star::packages::zip::ZipEntry &rEntry)
        throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException);
    sal_Int32       readCEN()
        throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException);
    sal_Int32       findEND()
        throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException);
};

#endif
<commit_msg>#89303# use new hash map and ZipEntry struct<commit_after>/*************************************************************************
 *
 *  $RCSfile: ZipFile.hxx,v $
 *
 *  $Revision: 1.15 $
 *
 *  last change: $Author: mtg $ $Date: 2001-09-14 14:45:19 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Martin Gallwey (gallwey@sun.com)
 *
 *
 ************************************************************************/
#ifndef _ZIP_FILE_HXX
#define _ZIP_FILE_HXX

#ifndef _BYTE_GRABBER_HXX_
#include <ByteGrabber.hxx>
#endif
#ifndef _HASHMAPS_HXX
#include <HashMaps.hxx>
#endif
#ifndef _INFLATER_HXX
#include <Inflater.hxx>
#endif
#ifndef _COM_SUN_STAR_PACKAGES_ZIP_ZIPEXCEPTION_HPP_
#include <com/sun/star/packages/zip/ZipException.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_NOSUCHELEMENTEXCEPTION_HPP_
#include <com/sun/star/container/NoSuchElementException.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_WRAPPEDTARGETEXCEPTION_HPP_
#include <com/sun/star/lang/WrappedTargetException.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _VOS_REF_H_
#include <vos/ref.hxx>
#endif
/*
 * We impose arbitrary but reasonable limit on ZIP files.
 */

#define ZIP_MAXNAMELEN 512
#define ZIP_MAXEXTRA 256
#define ZIP_MAXENTRIES (0x10000 - 2)

typedef void* rtlCipher;
class ZipEnumeration;
class EncryptionData;

class ZipFile
{
protected:
    ::rtl::OUString sName;          /* zip file name */
    ::rtl::OUString sComment;       /* zip file comment */
    EntryHash       aEntries;
    ByteGrabber     aGrabber;
    Inflater        aInflater;
    com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xStream;
    com::sun::star::uno::Reference < com::sun::star::io::XSeekable > xSeek;
    const ::com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > xFactory;

    com::sun::star::uno::Reference < com::sun::star::io::XInputStream >  createMemoryStream(
            ZipEntry & rEntry,
            const vos::ORef < EncryptionData > &rData,
            sal_Bool bRawStream );

    com::sun::star::uno::Reference < com::sun::star::io::XInputStream >  createFileStream(
            ZipEntry & rEntry,
            const vos::ORef < EncryptionData > &rData,
            sal_Bool bRawStream );
public:
    ZipFile( com::sun::star::uno::Reference < com::sun::star::io::XInputStream > &xInput,
             const com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > &xNewFactory,
             sal_Bool bInitialise)
        throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException);

    ~ZipFile();

    void setInputStream ( com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xNewStream );
    ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getRawStream(
            ZipEntry& rEntry,
            const vos::ORef < EncryptionData > &rData)
        throw(::com::sun::star::io::IOException, ::com::sun::star::packages::zip::ZipException, ::com::sun::star::uno::RuntimeException);

    static void StaticGetCipher ( const vos::ORef < EncryptionData > & xEncryptionData, rtlCipher &rCipher );

    ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream(
            ZipEntry& rEntry,
            const vos::ORef < EncryptionData > &rData)
        throw(::com::sun::star::io::IOException, ::com::sun::star::packages::zip::ZipException, ::com::sun::star::uno::RuntimeException);
    ::rtl::OUString SAL_CALL getName(  )
        throw(::com::sun::star::uno::RuntimeException);
    sal_Int32 SAL_CALL getSize(  )
        throw(::com::sun::star::uno::RuntimeException);

    ZipEnumeration * SAL_CALL entries(  );
protected:
    sal_Bool        readLOC ( ZipEntry &rEntry)
        throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException);
    sal_Int32       readCEN()
        throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException);
    sal_Int32       findEND()
        throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException);
};

#endif
<|endoftext|>