<commit_before>/** \brief Test cases for delete_unused_local_data
 *  \author Oliver Obenland (oliver.obenland@uni-tuebingen.de)
 *
 *  \copyright 2016 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#define BOOST_TEST_MODULE MarcRecord
#define BOOST_TEST_DYN_LINK

#include <boost/test/unit_test.hpp>
#include <vector>
#include "ExecUtil.h"

TEST(DeleteUnusedBlocks) {
    int exit_code(ExecUtil::Exec("/usr/local/bin/delete_unused_local_data", {"/usr/local/ub_tools/cpp/tests/data/LOK_withoutUsedBlock.mrc", "/tmp/output.mrc"}));
    BOOST_CHECK_EQUAL(exit_code, 0);

    exit_code = ExecUtil::Exec("/usr/bin/diff", {"/usr/local/ub_tools/cpp/tests/data/default.mrc", "/tmp/output.mrc"});
    BOOST_CHECK_EQUAL(exit_code, 0);
}

TEST(DeleteUnusedBlockAndLeaveOneBlock) {
    int exit_code(ExecUtil::Exec("/usr/local/bin/delete_unused_local_data", {"/usr/local/ub_tools/cpp/tests/data/LOK_withUsedBlock.mrc", "/tmp/output.mrc"}));
    BOOST_CHECK_EQUAL(exit_code, 0);

    exit_code = ExecUtil::Exec("/usr/bin/diff", {"/usr/local/ub_tools/cpp/tests/data/LOK_withUsedBlock.expected.mrc", "/tmp/output.mrc"});
    BOOST_CHECK_EQUAL(exit_code, 0);
}

TEST(DeleteNoBlock) {
    int exit_code(ExecUtil::Exec("/usr/local/bin/delete_unused_local_data", {"/usr/local/ub_tools/cpp/tests/data/default.mrc", "/tmp/output.mrc"}));
    BOOST_CHECK_EQUAL(exit_code, 0);

    exit_code = ExecUtil::Exec("/usr/bin/diff", {"/usr/local/ub_tools/cpp/tests/data/default.mrc", "/tmp/output.mrc"});
    BOOST_CHECK_EQUAL(exit_code, 0);
}
<commit_msg>Ported to our own test framework.<commit_after>/** \brief Test cases for delete_unused_local_data
 *  \author Oliver Obenland (oliver.obenland@uni-tuebingen.de)
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2016,2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <vector>
#include "ExecUtil.h"
#include "UnitTest.h"

TEST(DeleteUnusedBlocks) {
    int exit_code(ExecUtil::Exec("/usr/local/bin/delete_unused_local_data", {"/usr/local/ub_tools/cpp/tests/data/LOK_withoutUsedBlock.mrc", "/tmp/output.mrc"}));
    CHECK_EQ(exit_code, 0);

    exit_code = ExecUtil::Exec("/usr/bin/diff", {"/usr/local/ub_tools/cpp/tests/data/default.mrc", "/tmp/output.mrc"});
    CHECK_EQ(exit_code, 0);
}

TEST(DeleteUnusedBlockAndLeaveOneBlock) {
    int exit_code(ExecUtil::Exec("/usr/local/bin/delete_unused_local_data", {"/usr/local/ub_tools/cpp/tests/data/LOK_withUsedBlock.mrc", "/tmp/output.mrc"}));
    CHECK_EQ(exit_code, 0);

    exit_code = ExecUtil::Exec("/usr/bin/diff", {"/usr/local/ub_tools/cpp/tests/data/LOK_withUsedBlock.expected.mrc", "/tmp/output.mrc"});
    CHECK_EQ(exit_code, 0);
}

TEST(DeleteNoBlock) {
    int exit_code(ExecUtil::Exec("/usr/local/bin/delete_unused_local_data", {"/usr/local/ub_tools/cpp/tests/data/default.mrc", "/tmp/output.mrc"}));
    CHECK_EQ(exit_code, 0);

    exit_code = ExecUtil::Exec("/usr/bin/diff", {"/usr/local/ub_tools/cpp/tests/data/default.mrc", "/tmp/output.mrc"});
    CHECK_EQ(exit_code, 0);
}

TEST_MAIN(MarcRecord)
<|endoftext|>


<commit_before>#include "bam_util.h"
#include "char_util.h"

#ifdef __cplusplus
namespace dlib {
#endif

int abstract_single_iter(samFile *in, bam_hdr_t *hdr, samFile *out, single_aux_fn function, void *data)
{
    bam1_t *b;
    b = bam_init1();
    while (LIKELY(sam_read1(in, hdr, b) >= 0)) {
        if(function(b, data))
            continue;
        sam_write1(out, hdr, b);
    }
    bam_destroy1(b);
    return 0;
}

#ifdef __cplusplus

    std::string bam2cppstr(bam1_t *b)
    {
        char *qual, *seqbuf;
        int i;
        uint8_t *seq, *rvdata;
        uint32_t *pv, *fa;
        int8_t t;
        kstring_t ks = {1, 256uL, (char *)malloc(256uL)};
        ks.s[0] = '@', ks.s[1] = '\0';
        kputs(bam_get_qname(b), &ks);
        kputsn(" PV:B:I", 7uL, &ks);
        pv = (uint32_t *)dlib::array_tag(b, "PV");
        fa = (uint32_t *)dlib::array_tag(b, "FA");
        for(i = 0; i < b->core.l_qseq; ++i) ksprintf(&ks, ",%u", pv[i]);
        kputs("\tFA:B:I", &ks);
        for(i = 0; i < b->core.l_qseq; ++i) ksprintf(&ks, ",%u", fa[i]);
        ksprintf(&ks, "\tFM:i:%i\tFP:i:%i", bam_itag(b, "FM"), bam_itag(b, "FP"));
        write_tag_if_found(rvdata, b, "RV", ks);
        write_tag_if_found(rvdata, b, "NC", ks);
        write_tag_if_found(rvdata, b, "NP", ks);
        write_tag_if_found(rvdata, b, "DR", ks);
        kputc('\n', &ks);
        seq = bam_get_seq(b);
        seqbuf = (char *)malloc(b->core.l_qseq + 1);
        for (i = 0; i < b->core.l_qseq; ++i) seqbuf[i] = seq_nt16_str[bam_seqi(seq, i)];
        seqbuf[i] = '\0';
        if (b->core.flag & BAM_FREVERSE) { // reverse complement
            for(i = 0; i < b->core.l_qseq>>1; ++i) {
                t = seqbuf[b->core.l_qseq - i - 1];
                seqbuf[b->core.l_qseq - i - 1] = nuc_cmpl(seqbuf[i]);
                seqbuf[i] = nuc_cmpl(t);
            }
            if(b->core.l_qseq&1) seqbuf[i] = nuc_cmpl(seqbuf[i]);
        }
        seqbuf[b->core.l_qseq] = '\0';
        assert(strlen(seqbuf) == (uint64_t)b->core.l_qseq);
        kputs(seqbuf, &ks);
        kputs("\n+\n", &ks);
        qual = (char *)bam_get_qual(b);
        for(i = 0; i < b->core.l_qseq; ++i) seqbuf[i] = 33 + qual[i];
        if (b->core.flag & BAM_FREVERSE) { // reverse
            for (i = 0; i < b->core.l_qseq>>1; ++i) {
                t = seqbuf[b->core.l_qseq - 1 - i];
                seqbuf[b->core.l_qseq - 1 - i] = seqbuf[i];
                seqbuf[i] = t;
            }
        }
        assert(strlen(seqbuf) == (uint64_t)b->core.l_qseq);
        kputs(seqbuf, &ks), free(seqbuf);
        kputc('\n', &ks);
        std::string ret(ks.s), free(ks.s);
        return ret;
    }

    std::string get_SO(bam_hdr_t *hdr) {
        char *end, *so_start;
        std::string ret;
        if (strncmp(hdr->text, "@HD", 3) != 0) goto NA;
        if ((end = strchr(hdr->text, '\n')) == 0) goto NA;
        *end = '\0';

        if((so_start = strstr(hdr->text, "SO:")) == nullptr) goto NA;
        ret = std::string(so_start + strlen("SO:"));
        *end = '\n';
        return ret;

        NA:
        LOG_WARNING("Sort order not found. Returning N/A.\n");
        return std::string("N/A");
    }

    void resize_stack(tmp_stack_t *stack, size_t n) {
        if(n > stack->max) {
            stack->max = n;
            stack->a = (bam1_t **)realloc(stack->a, sizeof(bam1_t *) * n);
            if(!stack->a) LOG_EXIT("Failed to reallocate memory for %lu bam1_t * objects. Abort!\n", stack->max);
        } else if(n < stack->n){
            for(uint64_t i = stack->n;i > n;) free(stack->a[--i]->data);
            stack->max = n;
            stack->a = (bam1_t **)realloc(stack->a, sizeof(bam1_t *) * n);
        }
    }

    void abstract_pair_set(samFile *in, bam_hdr_t *hdr, samFile *ofp, std::unordered_set<pair_fn> functions)
    {
        bam1_t *b = bam_init1(), *b1 = bam_init1();
        while (LIKELY(sam_read1(in, hdr, b) >= 0)) {
            if(b->core.flag & (BAM_FSECONDARY | BAM_FSUPPLEMENTARY)) continue;
            if(b->core.flag & BAM_FREAD1) {
                bam_copy1(b1, b); continue;
            }
            for(auto f: functions) f(b1, b);
            sam_write1(ofp, hdr, b1), sam_write1(ofp, hdr, b);
        }
        bam_destroy1(b), bam_destroy1(b1);
    }

#endif

int abstract_pair_iter(samFile *in, bam_hdr_t *hdr, samFile *ofp, pair_aux_fn function, void *aux)
{
#if !NDEBUG
    size_t npairs = 0, nfailed = 0;
#endif
    bam1_t *b = bam_init1(), *b1 = bam_init1();
    while (LIKELY(sam_read1(in, hdr, b) >= 0)) {
        if(b->core.flag & (BAM_FSECONDARY | BAM_FSUPPLEMENTARY))
            continue;
        if(b->core.flag & BAM_FREAD1) {
            bam_copy1(b1, b); continue;
        }
#if !NDEBUG
        ++npairs;
#endif
        if(strcmp(bam_get_qname(b1), bam_get_qname(b)))
            LOG_EXIT("Is the bam name sorted? Reads in 'pair' don't have the same name (%s, %s). Abort!\n", bam_get_qname(b1), bam_get_qname(b));
        if(function(b1, b, aux) == 0) {
            sam_write1(ofp, hdr, b1), sam_write1(ofp, hdr, b);
        }
#if !NDEBUG
        else ++nfailed;
#endif
    }
    bam_destroy1(b), bam_destroy1(b1);
#if !NDEBUG
        LOG_DEBUG("Number of pairs considered: %lu. Number of pairs failed: %lu.\n", npairs, nfailed);
#endif
    return EXIT_SUCCESS;
}

int bampath_has_tag(char *bampath, const char *tag)
{
    samFile *fp = sam_open(bampath, "r");
    bam_hdr_t *header = sam_hdr_read(fp);
    if(!header || !fp) {
        LOG_EXIT("Could not open bam file at '%s' for reading. Abort!\n", bampath);
    }
    LOG_DEBUG("header: %p. fp: %p.\n", (void *)header, (void *)fp);
    bam1_t *b = bam_init1();
    if(sam_read1(fp, header, b) < 0) {
        LOG_EXIT("Empty bam file at '%s'. Abort!\n", bampath);
    }
    int ret = !!bam_aux_get(b, tag);
    bam_destroy1(b);
    bam_hdr_destroy(header);
    sam_close(fp);
    return ret;
}

void check_bam_tag_exit(char *bampath, const char *tag)
{
    if(strcmp(bampath, "-") && strcmp(bampath, "stdin")) {
        if(!bampath_has_tag(bampath, tag))
            LOG_EXIT("Required bam tag '%s' missing from bam file at path '%s'. Abort!\n", tag, bampath);
    } else {
        LOG_WARNING("Could not check for bam tag without exhausting a pipe. "
                    "Tag '%s' has not been verified.\n", tag);
    }
}

#ifdef __cplusplus
extern "C"
#endif
void add_pg_line(bam_hdr_t *hdr, int argc, char **argv,
                 const char *id, const char *version, const char *name, const char *ds) {
    char *tmp = hdr->text + hdr->l_text - 2;
    char *old_pg{nullptr};
    while(--tmp > hdr->text) {
        if(memcmp(tmp, "@PG", 3) == 0) {
            while(memcmp(++tmp, "ID:", 3));
            tmp += 3;
            char *end = tmp - 1;
            while(*++end != '\t'); // Zoom ahead to \t
            *end = '\0';
            old_pg = (char *)malloc(end - tmp + 1);
            memcpy(old_pg, tmp, end - tmp + 1);
            *end = '\t';
            break;
            // Found the last @PG line!
        }
    }
    kstring_t new_text{hdr->l_text, hdr->l_text, hdr->text}; // I now have ownership
    ksprintf(&new_text, "@PG\tID:%s\tPN:%s\tCL:", id, name ? name: id);
    kputs((const char *)argv[0], &new_text);
    for(int i = 1; i < argc; ++i) {
        kputc(' ', &new_text);
        kputs((const char *)argv[i], &new_text);
    }
    if(old_pg) {
        LOG_DEBUG("Found old pg: %s\n", old_pg);
        ksprintf(&new_text, "\tPP:%s", old_pg);
        free(old_pg);
    }
    if(ds) ksprintf(&new_text, "\tDS:%s", ds);
    if(version) ksprintf(&new_text, "\tVN:%s", version);
    kputc('\n', &new_text);
    hdr->text = new_text.s; // In case it was invalidated, reassign.
    hdr->l_text = new_text.l;
}

#ifdef __cplusplus
    /*
     * Applies fn
     */
    int BamHandle::for_each(std::function<int (bam1_t *, void *)> fn, BamHandle& ofp, void *data) {
        int ret;
        while(next() >= 0) {
            if((ret = fn(rec, data)) != 0) continue;
            ofp.write(rec);
        }
        return 0;
    }
    int BamHandle::for_each_pair(std::function<int (bam1_t *, bam1_t *, void *)> fn, BamHandle& ofp, void *data) {
        LOG_EXIT("Broken function.\n");
        int ret;
        bam1_t *r1 = bam_init1();
        while(next() >= 0) {
            if(rec->core.flag & BAM_FREAD1) {
                bam_copy1(r1, rec);
                continue;
            }
            if((rec->core.flag & BAM_FREAD2) == 0) continue;
            assert(strcmp(bam_get_qname(r1), bam_get_qname(rec)) == 0);
            if((ret = fn(r1, rec, data)) != 0) continue;
            if(strcmp(bam_get_qname(r1), bam_get_qname(rec)))
                LOG_EXIT("WTF\n");
            ofp.write(r1), ofp.write(rec);
        }
        bam_destroy1(r1);
        return 0;
    }
    int BamHandle::write() {return write(rec);}
    int bam_apply_function(char *infname, char *outfname,
                           std::function<int (bam1_t *, void *)> func, void *data, const char *mode) {
        BamHandle in(infname);
        BamHandle out(outfname, in.header, mode);
        return in.for_each(func, out, data);
    }
    int BamHandle::bed_plp_auto(khash_t(bed) *bed, std::function<int (const bam_pileup1_t *, int, void *)> fn,
                                BedPlpAuxBase *auxen) {
        plp = bam_plp_init((bam_plp_auto_f)&read_bam, (void *)auxen);
        auxen->handle = this;
        for(khiter_t ki = kh_begin(bed); ki != kh_end(bed); ++ki) {
            if(!kh_exist(bed, ki)) continue;
            for(unsigned i = 0; i < kh_val(bed, ki).n; ++i) {
                const int start = get_start(kh_val(bed, ki).intervals[i]);
                const int stop = get_stop(kh_val(bed, ki).intervals[i]);
                const int bed_tid = (int)kh_key(bed, ki);
                int tid, n_plp, pos;
                if(iter) hts_itr_destroy(iter);
                iter = bam_itr_queryi(idx, bed_tid, start, stop);
                bam_plp_reset(plp);
                while(bam_plp_auto(plp, &tid, &pos, &n_plp) != 0) {
                    assert(tid == bed_tid);
                    if(pos < start) continue;
                    if(pos >= stop) break;
                    fn(pileups, n_plp, auxen);
                }
            }
        }
        return 0;
    }
    /*
     * Does not own aux.
     */
    class BedPlpAux {
        BamHandle in;
        BamHandle out;
        BedPlpAuxBase *aux;
        khash_t(bed) *bed;
        BedPlpAux(char *inpath, char *outpath, char *bedpath, BedPlpAuxBase *data):
            in(inpath),
            out(outpath, in.header),
            aux(data),
            bed(parse_bed_hash(bedpath, in.header, data->padding))
        {
            if(!bed) LOG_EXIT("Failed to open bedfile %s. Abort!\n", bedpath);
        }
        ~BedPlpAux() {
            if(bed) bed_destroy_hash(bed);
        }
        int process(std::function<int (const bam_pileup1_t *, int, void *)> fn) {
            return in.bed_plp_auto(bed,fn, aux);
        }
    };
} /* namespace dlib */
#endif /* ifdef __cplusplus */
<commit_msg>Check each read in abstract pair iter to make sure that it's marked as a paired-end read.<commit_after>#include "bam_util.h"
#include "char_util.h"

#ifdef __cplusplus
namespace dlib {
#endif

int abstract_single_iter(samFile *in, bam_hdr_t *hdr, samFile *out, single_aux_fn function, void *data)
{
    bam1_t *b;
    b = bam_init1();
    while (LIKELY(sam_read1(in, hdr, b) >= 0)) {
        if(function(b, data))
            continue;
        sam_write1(out, hdr, b);
    }
    bam_destroy1(b);
    return 0;
}

#ifdef __cplusplus

    std::string bam2cppstr(bam1_t *b)
    {
        char *qual, *seqbuf;
        int i;
        uint8_t *seq, *rvdata;
        uint32_t *pv, *fa;
        int8_t t;
        kstring_t ks = {1, 256uL, (char *)malloc(256uL)};
        ks.s[0] = '@', ks.s[1] = '\0';
        kputs(bam_get_qname(b), &ks);
        kputsn(" PV:B:I", 7uL, &ks);
        pv = (uint32_t *)dlib::array_tag(b, "PV");
        fa = (uint32_t *)dlib::array_tag(b, "FA");
        for(i = 0; i < b->core.l_qseq; ++i) ksprintf(&ks, ",%u", pv[i]);
        kputs("\tFA:B:I", &ks);
        for(i = 0; i < b->core.l_qseq; ++i) ksprintf(&ks, ",%u", fa[i]);
        ksprintf(&ks, "\tFM:i:%i\tFP:i:%i", bam_itag(b, "FM"), bam_itag(b, "FP"));
        write_tag_if_found(rvdata, b, "RV", ks);
        write_tag_if_found(rvdata, b, "NC", ks);
        write_tag_if_found(rvdata, b, "NP", ks);
        write_tag_if_found(rvdata, b, "DR", ks);
        kputc('\n', &ks);
        seq = bam_get_seq(b);
        seqbuf = (char *)malloc(b->core.l_qseq + 1);
        for (i = 0; i < b->core.l_qseq; ++i) seqbuf[i] = seq_nt16_str[bam_seqi(seq, i)];
        seqbuf[i] = '\0';
        if (b->core.flag & BAM_FREVERSE) { // reverse complement
            for(i = 0; i < b->core.l_qseq>>1; ++i) {
                t = seqbuf[b->core.l_qseq - i - 1];
                seqbuf[b->core.l_qseq - i - 1] = nuc_cmpl(seqbuf[i]);
                seqbuf[i] = nuc_cmpl(t);
            }
            if(b->core.l_qseq&1) seqbuf[i] = nuc_cmpl(seqbuf[i]);
        }
        seqbuf[b->core.l_qseq] = '\0';
        assert(strlen(seqbuf) == (uint64_t)b->core.l_qseq);
        kputs(seqbuf, &ks);
        kputs("\n+\n", &ks);
        qual = (char *)bam_get_qual(b);
        for(i = 0; i < b->core.l_qseq; ++i) seqbuf[i] = 33 + qual[i];
        if (b->core.flag & BAM_FREVERSE) { // reverse
            for (i = 0; i < b->core.l_qseq>>1; ++i) {
                t = seqbuf[b->core.l_qseq - 1 - i];
                seqbuf[b->core.l_qseq - 1 - i] = seqbuf[i];
                seqbuf[i] = t;
            }
        }
        assert(strlen(seqbuf) == (uint64_t)b->core.l_qseq);
        kputs(seqbuf, &ks), free(seqbuf);
        kputc('\n', &ks);
        std::string ret(ks.s), free(ks.s);
        return ret;
    }

    std::string get_SO(bam_hdr_t *hdr) {
        char *end, *so_start;
        std::string ret;
        if (strncmp(hdr->text, "@HD", 3) != 0) goto NA;
        if ((end = strchr(hdr->text, '\n')) == 0) goto NA;
        *end = '\0';

        if((so_start = strstr(hdr->text, "SO:")) == nullptr) goto NA;
        ret = std::string(so_start + strlen("SO:"));
        *end = '\n';
        return ret;

        NA:
        LOG_WARNING("Sort order not found. Returning N/A.\n");
        return std::string("N/A");
    }

    void resize_stack(tmp_stack_t *stack, size_t n) {
        if(n > stack->max) {
            stack->max = n;
            stack->a = (bam1_t **)realloc(stack->a, sizeof(bam1_t *) * n);
            if(!stack->a) LOG_EXIT("Failed to reallocate memory for %lu bam1_t * objects. Abort!\n", stack->max);
        } else if(n < stack->n){
            for(uint64_t i = stack->n;i > n;) free(stack->a[--i]->data);
            stack->max = n;
            stack->a = (bam1_t **)realloc(stack->a, sizeof(bam1_t *) * n);
        }
    }

    void abstract_pair_set(samFile *in, bam_hdr_t *hdr, samFile *ofp, std::unordered_set<pair_fn> functions)
    {
        bam1_t *b = bam_init1(), *b1 = bam_init1();
        while (LIKELY(sam_read1(in, hdr, b) >= 0)) {
            if(b->core.flag & (BAM_FSECONDARY | BAM_FSUPPLEMENTARY)) continue;
            if(b->core.flag & BAM_FREAD1) {
                bam_copy1(b1, b); continue;
            }
            for(auto f: functions) f(b1, b);
            sam_write1(ofp, hdr, b1), sam_write1(ofp, hdr, b);
        }
        bam_destroy1(b), bam_destroy1(b1);
    }

#endif

int abstract_pair_iter(samFile *in, bam_hdr_t *hdr, samFile *ofp, pair_aux_fn function, void *aux)
{
#if !NDEBUG
    size_t npairs = 0, nfailed = 0;
#endif
    bam1_t *b = bam_init1(), *b1 = bam_init1();
    while (LIKELY(sam_read1(in, hdr, b) >= 0)) {
        if(UNLIKELY(b->core.flag & BAM_FPAIRED == 0))
            LOG_EXIT("Unpaired (single-end) read found in pairwise iterator. Abort!\n");
        if(b->core.flag & (BAM_FSECONDARY | BAM_FSUPPLEMENTARY))
            continue;
        if(b->core.flag & BAM_FREAD1) {
            bam_copy1(b1, b); continue;
        }
#if !NDEBUG
        ++npairs;
#endif
        if(strcmp(bam_get_qname(b1), bam_get_qname(b)))
            LOG_EXIT("Is the bam name sorted? Reads in 'pair' don't have the same name (%s, %s). Abort!\n", bam_get_qname(b1), bam_get_qname(b));
        if(function(b1, b, aux) == 0) {
            sam_write1(ofp, hdr, b1), sam_write1(ofp, hdr, b);
        }
#if !NDEBUG
        else ++nfailed;
#endif
    }
    bam_destroy1(b), bam_destroy1(b1);
#if !NDEBUG
        LOG_DEBUG("Number of pairs considered: %lu. Number of pairs failed: %lu.\n", npairs, nfailed);
#endif
    return EXIT_SUCCESS;
}

int bampath_has_tag(char *bampath, const char *tag)
{
    samFile *fp = sam_open(bampath, "r");
    bam_hdr_t *header = sam_hdr_read(fp);
    if(!header || !fp) {
        LOG_EXIT("Could not open bam file at '%s' for reading. Abort!\n", bampath);
    }
    LOG_DEBUG("header: %p. fp: %p.\n", (void *)header, (void *)fp);
    bam1_t *b = bam_init1();
    if(sam_read1(fp, header, b) < 0) {
        LOG_EXIT("Empty bam file at '%s'. Abort!\n", bampath);
    }
    int ret = !!bam_aux_get(b, tag);
    bam_destroy1(b);
    bam_hdr_destroy(header);
    sam_close(fp);
    return ret;
}

void check_bam_tag_exit(char *bampath, const char *tag)
{
    if(strcmp(bampath, "-") && strcmp(bampath, "stdin")) {
        if(!bampath_has_tag(bampath, tag))
            LOG_EXIT("Required bam tag '%s' missing from bam file at path '%s'. Abort!\n", tag, bampath);
    } else {
        LOG_WARNING("Could not check for bam tag without exhausting a pipe. "
                    "Tag '%s' has not been verified.\n", tag);
    }
}

#ifdef __cplusplus
extern "C"
#endif
void add_pg_line(bam_hdr_t *hdr, int argc, char **argv,
                 const char *id, const char *version, const char *name, const char *ds) {
    char *tmp = hdr->text + hdr->l_text - 2;
    char *old_pg{nullptr};
    while(--tmp > hdr->text) {
        if(memcmp(tmp, "@PG", 3) == 0) {
            while(memcmp(++tmp, "ID:", 3));
            tmp += 3;
            char *end = tmp - 1;
            while(*++end != '\t'); // Zoom ahead to \t
            *end = '\0';
            old_pg = (char *)malloc(end - tmp + 1);
            memcpy(old_pg, tmp, end - tmp + 1);
            *end = '\t';
            break;
            // Found the last @PG line!
        }
    }
    kstring_t new_text{hdr->l_text, hdr->l_text, hdr->text}; // I now have ownership
    ksprintf(&new_text, "@PG\tID:%s\tPN:%s\tCL:", id, name ? name: id);
    kputs((const char *)argv[0], &new_text);
    for(int i = 1; i < argc; ++i) {
        kputc(' ', &new_text);
        kputs((const char *)argv[i], &new_text);
    }
    if(old_pg) {
        LOG_DEBUG("Found old pg: %s\n", old_pg);
        ksprintf(&new_text, "\tPP:%s", old_pg);
        free(old_pg);
    }
    if(ds) ksprintf(&new_text, "\tDS:%s", ds);
    if(version) ksprintf(&new_text, "\tVN:%s", version);
    kputc('\n', &new_text);
    hdr->text = new_text.s; // In case it was invalidated, reassign.
    hdr->l_text = new_text.l;
}

#ifdef __cplusplus
    /*
     * Applies fn
     */
    int BamHandle::for_each(std::function<int (bam1_t *, void *)> fn, BamHandle& ofp, void *data) {
        int ret;
        while(next() >= 0) {
            if((ret = fn(rec, data)) != 0) continue;
            ofp.write(rec);
        }
        return 0;
    }
    int BamHandle::for_each_pair(std::function<int (bam1_t *, bam1_t *, void *)> fn, BamHandle& ofp, void *data) {
        LOG_EXIT("Broken function.\n");
        int ret;
        bam1_t *r1 = bam_init1();
        while(next() >= 0) {
            if(rec->core.flag & BAM_FREAD1) {
                bam_copy1(r1, rec);
                continue;
            }
            if((rec->core.flag & BAM_FREAD2) == 0) continue;
            assert(strcmp(bam_get_qname(r1), bam_get_qname(rec)) == 0);
            if((ret = fn(r1, rec, data)) != 0) continue;
            if(strcmp(bam_get_qname(r1), bam_get_qname(rec)))
                LOG_EXIT("WTF\n");
            ofp.write(r1), ofp.write(rec);
        }
        bam_destroy1(r1);
        return 0;
    }
    int BamHandle::write() {return write(rec);}
    int bam_apply_function(char *infname, char *outfname,
                           std::function<int (bam1_t *, void *)> func, void *data, const char *mode) {
        BamHandle in(infname);
        BamHandle out(outfname, in.header, mode);
        return in.for_each(func, out, data);
    }
    int BamHandle::bed_plp_auto(khash_t(bed) *bed, std::function<int (const bam_pileup1_t *, int, void *)> fn,
                                BedPlpAuxBase *auxen) {
        plp = bam_plp_init((bam_plp_auto_f)&read_bam, (void *)auxen);
        auxen->handle = this;
        for(khiter_t ki = kh_begin(bed); ki != kh_end(bed); ++ki) {
            if(!kh_exist(bed, ki)) continue;
            for(unsigned i = 0; i < kh_val(bed, ki).n; ++i) {
                const int start = get_start(kh_val(bed, ki).intervals[i]);
                const int stop = get_stop(kh_val(bed, ki).intervals[i]);
                const int bed_tid = (int)kh_key(bed, ki);
                int tid, n_plp, pos;
                if(iter) hts_itr_destroy(iter);
                iter = bam_itr_queryi(idx, bed_tid, start, stop);
                bam_plp_reset(plp);
                while(bam_plp_auto(plp, &tid, &pos, &n_plp) != 0) {
                    assert(tid == bed_tid);
                    if(pos < start) continue;
                    if(pos >= stop) break;
                    fn(pileups, n_plp, auxen);
                }
            }
        }
        return 0;
    }
    /*
     * Does not own aux.
     */
    class BedPlpAux {
        BamHandle in;
        BamHandle out;
        BedPlpAuxBase *aux;
        khash_t(bed) *bed;
        BedPlpAux(char *inpath, char *outpath, char *bedpath, BedPlpAuxBase *data):
            in(inpath),
            out(outpath, in.header),
            aux(data),
            bed(parse_bed_hash(bedpath, in.header, data->padding))
        {
            if(!bed) LOG_EXIT("Failed to open bedfile %s. Abort!\n", bedpath);
        }
        ~BedPlpAux() {
            if(bed) bed_destroy_hash(bed);
        }
        int process(std::function<int (const bam_pileup1_t *, int, void *)> fn) {
            return in.bed_plp_auto(bed,fn, aux);
        }
    };
} /* namespace dlib */
#endif /* ifdef __cplusplus */
<|endoftext|>


<commit_before>/*
    Privacy Plugin - Filter messages

    Copyright (c) 2006 by Andre Duffeck <andre@duffeck.de>
    Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel@kde.org>

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

#include <kgenericfactory.h>
#include <kicon.h>
#include <knotification.h>

#include "kopetecontact.h"
#include "kopetemetacontact.h"
#include "kopetemessage.h"
#include "kopetemessageevent.h"
#include "kopetechatsessionmanager.h"
#include "kopeteprotocol.h"
#include "kopetecontactlist.h"
#include "kopetepluginmanager.h"
#include "privacymessagehandler.h"
#include "privacyconfig.h"

#include "privacyplugin.h"

typedef KGenericFactory<PrivacyPlugin> PrivacyPluginFactory;
K_EXPORT_COMPONENT_FACTORY( kopete_privacy, PrivacyPluginFactory( "kopete_privacy" )  )
PrivacyPlugin * PrivacyPlugin::pluginStatic_ = 0L;

PrivacyPlugin::PrivacyPlugin( QObject *parent, const QStringList & )
: Kopete::Plugin( PrivacyPluginFactory::instance(), parent )
{
	kDebug(14313) << k_funcinfo << endl;
	if( !pluginStatic_ )
		pluginStatic_ = this;

	KAction *addToWhiteList = new KAction( KIcon("privacy_whitelist"), i18n("Add to WhiteList" ),
		actionCollection(), "addToWhiteList" );
	connect(addToWhiteList, SIGNAL(triggered(bool)), this, SLOT(slotAddToWhiteList()));
	connect(Kopete::ContactList::self(), SIGNAL(metaContactSelected(bool)),
		addToWhiteList, SLOT(setEnabled(bool)));
	KAction *addToBlackList = new KAction( KIcon("privacy_blacklist"), i18n("Add to BlackList" ),
		actionCollection(), "addToBlackList" );
	connect(addToBlackList, SIGNAL(triggered(bool)), this, SLOT(slotAddToBlackList()));
	connect(Kopete::ContactList::self(), SIGNAL(metaContactSelected(bool)),
		addToBlackList, SLOT(setEnabled(bool)));

	setXMLFile("privacyui.rc");

	m_inboundHandler = new PrivacyMessageHandlerFactory( Kopete::Message::Inbound,
		Kopete::MessageHandlerFactory::InStageStart, this, SLOT( slotIncomingMessage( Kopete::MessageEvent * ) ) );

	connect( this, SIGNAL( settingsChanged() ), this, SLOT( slotSettingsChanged() ) );
}

PrivacyPlugin::~PrivacyPlugin()
{
	kDebug(14313) << k_funcinfo << endl;
	pluginStatic_ = 0L;
	delete m_inboundHandler;
}

PrivacyPlugin *PrivacyPlugin::plugin()
{
	return pluginStatic_ ;
}

PrivacyConfig *PrivacyPlugin::config()
{
	return PrivacyConfig::self();
}

void PrivacyPlugin::slotSettingsChanged()
{
	PrivacyConfig::self()->readConfig();
}

void PrivacyPlugin::slotAddToWhiteList()
{
	QStringList whitelist = PrivacyConfig::whiteList();
	foreach( Kopete::MetaContact *metacontact, Kopete::ContactList::self()->selectedMetaContacts() )
	{
		foreach( Kopete::Contact *contact, metacontact->contacts() )
		{
			QString entry( contact->protocol()->pluginId() + ":" + contact->contactId() );
			if( !whitelist.contains( entry ) )
				whitelist.append( entry );
		}
	}
	PrivacyConfig::setWhiteList( whitelist );
	PrivacyConfig::self()->writeConfig();
}

void PrivacyPlugin::slotAddToBlackList()
{
	QStringList blacklist = PrivacyConfig::blackList();
	foreach( Kopete::MetaContact *metacontact, Kopete::ContactList::self()->selectedMetaContacts() )
	{
		foreach( Kopete::Contact *contact, metacontact->contacts() )
		{
			QString entry( contact->protocol()->pluginId() + ":" + contact->contactId() );
			if( !blacklist.contains( entry ) )
				blacklist.append( entry );
		}
	}
	PrivacyConfig::setBlackList( blacklist );
	PrivacyConfig::self()->writeConfig();
}

void PrivacyPlugin::slotIncomingMessage( Kopete::MessageEvent *event )
{
	Kopete::Message msg = event->message();

	if( msg.direction() == Kopete::Message::Outbound ||
		msg.direction() == Kopete::Message::Internal )
		return;

	// Verify sender
	if( PrivacyConfig::sender_AllowNoneButWhiteList() )
	{
		if( !PrivacyConfig::whiteList().contains( msg.from()->protocol()->pluginId() + ":" + msg.from()->contactId() ) )
		{
			kDebug(14313) << k_funcinfo << "Message from " << msg.from()->protocol()->pluginId() << ":" << msg.from()->contactId() << " dropped (not whitelisted)" << endl;
			KNotification::event( "message_dropped", i18n("A message from %1 was dropped, because this contact is not on your whitelist.") );
			event->discard();
			return;
		}
	}
	else if( PrivacyConfig::sender_AllowAllButBlackList() )
	{
		if( PrivacyConfig::blackList().contains( msg.from()->protocol()->pluginId() + ":" + msg.from()->contactId() ) )
		{
			kDebug(14313) << k_funcinfo << "Message from " << msg.from()->protocol()->pluginId() << ":" << msg.from()->contactId() << " dropped (blacklisted)" << endl;
			KNotification::event( "message_dropped", i18n("A message from %1 was dropped, because this contact is on your blacklist.") );
			event->discard();
			return;
		}
	}
	else if( PrivacyConfig::sender_AllowNoneButContactList() )
	{
		if( msg.from()->metaContact()->isTemporary() )
		{
			kDebug(14313) << k_funcinfo << "Message from " << msg.from()->contactId() << " dropped (not on the contactlist)" << endl;
			KNotification::event( "message_dropped", i18n("A message from %1 was dropped, because this contact is not on your contactlist.") );
			event->discard();
			return;
		}
	}

	// Verify content
	if( PrivacyConfig::content_DropIfAny() )
	{
		foreach(QString word, PrivacyConfig::dropIfAny().split(',') )
		{
			if( msg.plainBody().contains( word ) )
			{
				kDebug(14313) << k_funcinfo << "Message dropped because it contained: " << word << endl;
				KNotification::event( "message_dropped", i18n("A message from %1 was dropped, because it contained a blacklisted word.") );
				event->discard();
				return;
			}
		}
	}

	if( PrivacyConfig::content_DropIfAll() )
	{
		bool drop = true;
		foreach(QString word, PrivacyConfig::dropIfAll().split(',') )
		{
			if( !msg.plainBody().contains( word ) )
			{
				drop = false;
				break;
			}
		}
		if( drop )
		{
			kDebug(14313) << k_funcinfo << "Message dropped because it contained blacklisted words." << endl;
				KNotification::event( "message_dropped", i18n("A message from %1 was dropped, because it contained blacklisted words.") );
			event->discard();
			return;
		}
	}
}

#include "privacyplugin.moc"
<commit_msg>ups :)<commit_after>/*
    Privacy Plugin - Filter messages

    Copyright (c) 2006 by Andre Duffeck <andre@duffeck.de>
    Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel@kde.org>

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

#include <kgenericfactory.h>
#include <kicon.h>
#include <knotification.h>

#include "kopetecontact.h"
#include "kopetemetacontact.h"
#include "kopetemessage.h"
#include "kopetemessageevent.h"
#include "kopetechatsessionmanager.h"
#include "kopeteprotocol.h"
#include "kopetecontactlist.h"
#include "kopetepluginmanager.h"
#include "privacymessagehandler.h"
#include "privacyconfig.h"

#include "privacyplugin.h"

typedef KGenericFactory<PrivacyPlugin> PrivacyPluginFactory;
K_EXPORT_COMPONENT_FACTORY( kopete_privacy, PrivacyPluginFactory( "kopete_privacy" )  )
PrivacyPlugin * PrivacyPlugin::pluginStatic_ = 0L;

PrivacyPlugin::PrivacyPlugin( QObject *parent, const QStringList & )
: Kopete::Plugin( PrivacyPluginFactory::instance(), parent )
{
	kDebug(14313) << k_funcinfo << endl;
	if( !pluginStatic_ )
		pluginStatic_ = this;

	KAction *addToWhiteList = new KAction( KIcon("privacy_whitelist"), i18n("Add to WhiteList" ),
		actionCollection(), "addToWhiteList" );
	connect(addToWhiteList, SIGNAL(triggered(bool)), this, SLOT(slotAddToWhiteList()));
	connect(Kopete::ContactList::self(), SIGNAL(metaContactSelected(bool)),
		addToWhiteList, SLOT(setEnabled(bool)));
	KAction *addToBlackList = new KAction( KIcon("privacy_blacklist"), i18n("Add to BlackList" ),
		actionCollection(), "addToBlackList" );
	connect(addToBlackList, SIGNAL(triggered(bool)), this, SLOT(slotAddToBlackList()));
	connect(Kopete::ContactList::self(), SIGNAL(metaContactSelected(bool)),
		addToBlackList, SLOT(setEnabled(bool)));

	setXMLFile("privacyui.rc");

	m_inboundHandler = new PrivacyMessageHandlerFactory( Kopete::Message::Inbound,
		Kopete::MessageHandlerFactory::InStageStart, this, SLOT( slotIncomingMessage( Kopete::MessageEvent * ) ) );

	connect( this, SIGNAL( settingsChanged() ), this, SLOT( slotSettingsChanged() ) );
}

PrivacyPlugin::~PrivacyPlugin()
{
	kDebug(14313) << k_funcinfo << endl;
	pluginStatic_ = 0L;
	delete m_inboundHandler;
}

PrivacyPlugin *PrivacyPlugin::plugin()
{
	return pluginStatic_ ;
}

PrivacyConfig *PrivacyPlugin::config()
{
	return PrivacyConfig::self();
}

void PrivacyPlugin::slotSettingsChanged()
{
	PrivacyConfig::self()->readConfig();
}

void PrivacyPlugin::slotAddToWhiteList()
{
	QStringList whitelist = PrivacyConfig::whiteList();
	foreach( Kopete::MetaContact *metacontact, Kopete::ContactList::self()->selectedMetaContacts() )
	{
		foreach( Kopete::Contact *contact, metacontact->contacts() )
		{
			QString entry( contact->protocol()->pluginId() + ":" + contact->contactId() );
			if( !whitelist.contains( entry ) )
				whitelist.append( entry );
		}
	}
	PrivacyConfig::setWhiteList( whitelist );
	PrivacyConfig::self()->writeConfig();
}

void PrivacyPlugin::slotAddToBlackList()
{
	QStringList blacklist = PrivacyConfig::blackList();
	foreach( Kopete::MetaContact *metacontact, Kopete::ContactList::self()->selectedMetaContacts() )
	{
		foreach( Kopete::Contact *contact, metacontact->contacts() )
		{
			QString entry( contact->protocol()->pluginId() + ":" + contact->contactId() );
			if( !blacklist.contains( entry ) )
				blacklist.append( entry );
		}
	}
	PrivacyConfig::setBlackList( blacklist );
	PrivacyConfig::self()->writeConfig();
}

void PrivacyPlugin::slotIncomingMessage( Kopete::MessageEvent *event )
{
	Kopete::Message msg = event->message();

	if( msg.direction() == Kopete::Message::Outbound ||
		msg.direction() == Kopete::Message::Internal )
		return;

	// Verify sender
	if( PrivacyConfig::sender_AllowNoneButWhiteList() )
	{
		if( !PrivacyConfig::whiteList().contains( msg.from()->protocol()->pluginId() + ":" + msg.from()->contactId() ) )
		{
			kDebug(14313) << k_funcinfo << "Message from " << msg.from()->protocol()->pluginId() << ":" << msg.from()->contactId() << " dropped (not whitelisted)" << endl;
			KNotification::event( "message_dropped", i18n("A message from %1 was dropped, because this contact is not on your whitelist.").arg(msg.from()->contactId()) );
			event->discard();
			return;
		}
	}
	else if( PrivacyConfig::sender_AllowAllButBlackList() )
	{
		if( PrivacyConfig::blackList().contains( msg.from()->protocol()->pluginId() + ":" + msg.from()->contactId() ) )
		{
			kDebug(14313) << k_funcinfo << "Message from " << msg.from()->protocol()->pluginId() << ":" << msg.from()->contactId() << " dropped (blacklisted)" << endl;
			KNotification::event( "message_dropped", i18n("A message from %1 was dropped, because this contact is on your blacklist.").arg(msg.from()->contactId()) );
			event->discard();
			return;
		}
	}
	else if( PrivacyConfig::sender_AllowNoneButContactList() )
	{
		if( msg.from()->metaContact()->isTemporary() )
		{
			kDebug(14313) << k_funcinfo << "Message from " << msg.from()->contactId() << " dropped (not on the contactlist)" << endl;
			KNotification::event( "message_dropped", i18n("A message from %1 was dropped, because this contact is not on your contactlist.").arg(msg.from()->contactId()) );
			event->discard();
			return;
		}
	}

	// Verify content
	if( PrivacyConfig::content_DropIfAny() )
	{
		foreach(QString word, PrivacyConfig::dropIfAny().split(',') )
		{
			if( msg.plainBody().contains( word ) )
			{
				kDebug(14313) << k_funcinfo << "Message dropped because it contained: " << word << endl;
				KNotification::event( "message_dropped", i18n("A message from %1 was dropped, because it contained a blacklisted word.").arg(msg.from()->contactId()) );
				event->discard();
				return;
			}
		}
	}

	if( PrivacyConfig::content_DropIfAll() )
	{
		bool drop = true;
		foreach(QString word, PrivacyConfig::dropIfAll().split(',') )
		{
			if( !msg.plainBody().contains( word ) )
			{
				drop = false;
				break;
			}
		}
		if( drop )
		{
			kDebug(14313) << k_funcinfo << "Message dropped because it contained blacklisted words." << endl;
				KNotification::event( "message_dropped", i18n("A message from %1 was dropped, because it contained blacklisted words.").arg(msg.from()->contactId()) );
			event->discard();
			return;
		}
	}
}

#include "privacyplugin.moc"
<|endoftext|>


<commit_before>#include "BadGuyContainer.hpp"
#include "SDL.hpp" // randomNumberBetween()
#include "Window.hpp"

BadGuyContainer::BadGuyContainer(unsigned int maxAmmount, Rectangle *gameArea, PlatformManager *platforms) :
    venusCount(0),
    griffinCount(0),
    maxAmmount(maxAmmount),
    currentAmmount(0),
    gameArea(gameArea),
    platforms(platforms)
{
    unsigned int i;
    int occupied = 0; // Say's if platform already occupied by Venus copy

    // ADDING EVERYONE
    // for (i = 0; i < this->maxAmmount; i++)
    // {
    //     Point p;

    //     if ((i % 2) == 0)
    //         this->type = BadGuy::GRIFFIN;
    //     else
    //         this->type = BadGuy::VENUS;

    //     if (this->type == BadGuy::GRIFFIN)
    //     {
    //         p.x = SDL::randomNumberBetween(0, this->gameArea->w);
    //         p.y = SDL::randomNumberBetween(0, this->gameArea->h);
    //     }
    //     else // VENUS
    //     {
    //         std::list<Platform*>::iterator it = this->platforms->container->platforms.begin();
    //         int j = 0;
    //         while (j != occupied && it != this->platforms->container->platforms.end())
    //         {
    //             it++;
    //             j++;
    //         }

    //         if (it != this->platforms->container->platforms.end() &&
    //             (*it)->type != Platform::VANISHING                &&
    //             (*it)->type != Platform::MOVABLE)
    //         {
    //             p = (*it)->box->topLeft;
    //         }
    //         else
    //         {
    //             p.x = 0;
    //             p.y = 0;
    //         }
    //         occupied++;
    //     }
    //     if (p.x != 0 && p.y != 0)
    //         this->add(p, type);
    // }
 }
BadGuyContainer::~BadGuyContainer()
{
    unsigned int size = this->badguy.size();
    for (unsigned int i = 0; i < size; i++)
        if (this->badguy[i])
            delete (this->badguy[i]);
}
void BadGuyContainer::add(Point p, BadGuy::BadGuyType type)
{
    std::vector<BadGuy*>::iterator it;
    it = this->badguy.begin();

    if (type == BadGuy::VENUS)
    {
        BadGuyVenus* v = new BadGuyVenus(p.x, p.y - 391, 142, 391, 1, Config::playerAcceleration);
        it = this->badguy.insert(it, v);

        this->venus.push_back(v);
        Log::verbose("Venus");
    }
    else
    {
        BadGuyGriffin* g = new BadGuyGriffin(p.x - 292, p.y - 215, 292, 215, 1, Config::playerAcceleration);
        it = this->badguy.insert(it, g);

        this->griffin.push_back(g);
        Log::verbose("Griffin");
        (*it)->setHorizontalLimit(60, this->gameArea->w - 119);
        (*it)->setVerticalLimit(215, rand()%this->gameArea->h);
    }

    Log::verbose("BadGuy::add (" + SDL::intToString(p.x) +
                 ", " + SDL::intToString(p.y) +
                 ") " );
}
void BadGuyContainer::render(float cameraX, float cameraY)
{
    this->cameraY = cameraY;

    unsigned int size = this->badguy.size();
    for (unsigned int i = 0; i < size; i++)
        if (this->badguy[i])
            this->badguy[i]->render(cameraX, cameraY);
}
void BadGuyContainer::update(float dt)
{
    unsigned int size = this->badguy.size();
    for (unsigned int i = 0; i < size; i++)
        if (this->badguy[i])
        {
            // Will kill it if it's below current camera level
            if ((this->badguy[i]->box->bottom) > (this->cameraY + Window::height + 100))
                this->badguy[i]->die();

            if (this->badguy[i]->died())
            {
                if (this->badguy[i]->type == BadGuy::VENUS)
                    this->venusCount--;
                else
                    this->griffinCount--;

                delete this->badguy[i];
                this->badguy[i] = NULL;
            }
            else
            {
                this->badguy[i]->update(dt);
                this->badguy[i]->commitMovement();
            }
        }
}
void BadGuyContainer::addVenus()
{
    for (std::list<Platform*>::iterator it = this->platforms->container->platforms.begin();
         it != this->platforms->container->platforms.end();
         it++)
    {
        // Kinda limited, right?
        if (((*it)->type == Platform::VANISHING) ||
            ((*it)->type == Platform::MOVABLE)   ||
            ((*it)->type == Platform::CLOUD)     ||
            ((*it)->occupied))
            continue;

        // Adding only on platforms above the current camera level
        if ((*it)->box->bottom < this->cameraY)
        {
            this->addVenusTo((*it));
            break;
        }
    }
}
void BadGuyContainer::addVenusTo(Platform* p)
{
    p->occupied = true;

    BadGuyVenus* v = new BadGuyVenus(p->box->center.x - 30,
                                     p->box->top - 270,
                                     98,
                                     270,
                                     1,
                                     Config::playerAcceleration);
    this->badguy.push_back(v);
    this->venusCount++;

    Log::verbose("Venus");
    Log::verbose("BadGuy::add (" + SDL::intToString(p->box->x) +
                 ", " + SDL::intToString(p->box->y) +
                 ") " );
}
void BadGuyContainer::addGriffin()
{
    Point p;
    p.x = SDL::randomNumberBetween(0, this->gameArea->w);
    p.y = SDL::randomNumberBetween(this->cameraY - 100,
                                   this->cameraY);

    BadGuyGriffin* g = new BadGuyGriffin(p.x - 292,
                                         p.y - 215,
                                         292,
                                         215,
                                         1,
                                         Config::playerAcceleration);

    g->setHorizontalLimit(60, this->gameArea->w - 119);
//    g->setVerticalLimit(215, SDL::randomNumberBetween(p.y - 1000, p.y + 1000));

    this->badguy.push_back(g);
    this->griffinCount++;

    Log::verbose("Griffin");
    Log::verbose("BadGuy::add (" + SDL::intToString(p.x) +
                 ", " + SDL::intToString(p.y) +
                 ") " );
}

<commit_msg>gambiarras<commit_after>#include "BadGuyContainer.hpp"
#include "SDL.hpp" // randomNumberBetween()
#include "Window.hpp"

BadGuyContainer::BadGuyContainer(unsigned int maxAmmount, Rectangle *gameArea, PlatformManager *platforms) :
    venusCount(0),
    griffinCount(0),
    maxAmmount(maxAmmount),
    currentAmmount(0),
    gameArea(gameArea),
    platforms(platforms)
{
    unsigned int i;
    int occupied = 0; // Say's if platform already occupied by Venus copy

    this->addGriffin();
    this->addGriffin();
    this->addGriffin();
    this->addGriffin();
    this->addGriffin();
    this->addGriffin();
    this->addGriffin();
    this->addGriffin();
    this->addGriffin();
    this->addGriffin();
    // ADDING EVERYONE
    // for (i = 0; i < this->maxAmmount; i++)
    // {
    //     Point p;

    //     if ((i % 2) == 0)
    //         this->type = BadGuy::GRIFFIN;
    //     else
    //         this->type = BadGuy::VENUS;

    //     if (this->type == BadGuy::GRIFFIN)
    //     {
    //         p.x = SDL::randomNumberBetween(0, this->gameArea->w);
    //         p.y = SDL::randomNumberBetween(0, this->gameArea->h);
    //     }
    //     else // VENUS
    //     {
    //         std::list<Platform*>::iterator it = this->platforms->container->platforms.begin();
    //         int j = 0;
    //         while (j != occupied && it != this->platforms->container->platforms.end())
    //         {
    //             it++;
    //             j++;
    //         }

    //         if (it != this->platforms->container->platforms.end() &&
    //             (*it)->type != Platform::VANISHING                &&
    //             (*it)->type != Platform::MOVABLE)
    //         {
    //             p = (*it)->box->topLeft;
    //         }
    //         else
    //         {
    //             p.x = 0;
    //             p.y = 0;
    //         }
    //         occupied++;
    //     }
    //     if (p.x != 0 && p.y != 0)
    //         this->add(p, type);
    // }
 }
BadGuyContainer::~BadGuyContainer()
{
    unsigned int size = this->badguy.size();
    for (unsigned int i = 0; i < size; i++)
        if (this->badguy[i])
            delete (this->badguy[i]);
}
void BadGuyContainer::add(Point p, BadGuy::BadGuyType type)
{
    std::vector<BadGuy*>::iterator it;
    it = this->badguy.begin();

    if (type == BadGuy::VENUS)
    {
        BadGuyVenus* v = new BadGuyVenus(p.x, p.y - 391, 142, 391, 1, Config::playerAcceleration);
        it = this->badguy.insert(it, v);

        this->venus.push_back(v);
        Log::verbose("Venus");
    }
    else
    {
        BadGuyGriffin* g = new BadGuyGriffin(p.x - 292, p.y - 215, 292, 215, 1, Config::playerAcceleration);
        it = this->badguy.insert(it, g);

        this->griffin.push_back(g);
        Log::verbose("Griffin");
        (*it)->setHorizontalLimit(60, this->gameArea->w - 119);
        (*it)->setVerticalLimit(215, rand()%this->gameArea->h);
    }

    Log::verbose("BadGuy::add (" + SDL::intToString(p.x) +
                 ", " + SDL::intToString(p.y) +
                 ") " );
}
void BadGuyContainer::render(float cameraX, float cameraY)
{
    this->cameraY = cameraY;

    unsigned int size = this->badguy.size();
    for (unsigned int i = 0; i < size; i++)
        if (this->badguy[i])
            this->badguy[i]->render(cameraX, cameraY);
}
void BadGuyContainer::update(float dt)
{
    unsigned int size = this->badguy.size();
    for (unsigned int i = 0; i < size; i++)
        if (this->badguy[i])
        {
            // Will kill it if it's below current camera level
            if ((this->badguy[i]->box->bottom) > (this->cameraY + Window::height + 100))
                this->badguy[i]->die();

            if (this->badguy[i]->died())
            {
                if (this->badguy[i]->type == BadGuy::VENUS)
                    this->venusCount--;
                else
                    this->griffinCount--;

                delete this->badguy[i];
                this->badguy[i] = NULL;
            }
            else
            {
                this->badguy[i]->update(dt);
                this->badguy[i]->commitMovement();
            }
        }
}
void BadGuyContainer::addVenus()
{
    for (std::list<Platform*>::iterator it = this->platforms->container->platforms.begin();
         it != this->platforms->container->platforms.end();
         it++)
    {
        // Kinda limited, right?
        if (((*it)->type == Platform::VANISHING) ||
            ((*it)->type == Platform::MOVABLE)   ||
            ((*it)->type == Platform::CLOUD)     ||
            ((*it)->occupied))
            continue;

        // Adding only on platforms above the current camera level
        if ((*it)->box->bottom < this->cameraY)
        {
            this->addVenusTo((*it));
            break;
        }
    }
}
void BadGuyContainer::addVenusTo(Platform* p)
{
    p->occupied = true;

    BadGuyVenus* v = new BadGuyVenus(p->box->center.x - 30,
                                     p->box->top - 270,
                                     98,
                                     270,
                                     1,
                                     Config::playerAcceleration);
    this->badguy.push_back(v);
    this->venusCount++;

    Log::verbose("Venus");
    Log::verbose("BadGuy::add (" + SDL::intToString(p->box->x) +
                 ", " + SDL::intToString(p->box->y) +
                 ") " );
}
void BadGuyContainer::addGriffin()
{
    Point p;
    p.x = SDL::randomNumberBetween(0, this->gameArea->w);
    p.y = SDL::randomNumberBetween(0, this->gameArea->h);

    BadGuyGriffin* g = new BadGuyGriffin(p.x - 292,
                                         p.y - 215,
                                         292,
                                         215,
                                         1,
                                         Config::playerAcceleration);

    g->setHorizontalLimit(60, this->gameArea->w - 119);
    g->setVerticalLimit(215, SDL::randomNumberBetween(0, this->gameArea->h));

    this->badguy.push_back(g);
    this->griffinCount++;

    Log::verbose("Griffin");
    Log::verbose("BadGuy::add (" + SDL::intToString(p.x) +
                 ", " + SDL::intToString(p.y) +
                 ") " );
}

<|endoftext|>


<commit_before>///
/// SymbolicMath toolkit
/// (c) 2017-2020 by Daniel Schwen
///

#include "SMTransformHash.h"
#include "SMFunction.h"

namespace SymbolicMath
{

template <typename T>
Hash<T>::Hash(Function<T> & fb) : Transform<T>(fb)
{
  apply();
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, SymbolData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  setHash(node, salt ^ std::hash<std::string>{}(data._name));
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, UnaryOperatorData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  data._args[0].apply(*this);
  setHash(node, salt ^ std::hash<UnaryOperatorType>{}(data._type) ^ (_hash << 1));
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, BinaryOperatorData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  data._args[0].apply(*this);
  const auto hashA = _hash << 1;
  data._args[1].apply(*this);
  const auto hashB = _hash << 2;
  setHash(node, salt ^ std::hash<BinaryOperatorType>{}(data._type) ^ hashA ^ hashB);
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, MultinaryOperatorData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  auto h = salt ^ std::hash<MultinaryOperatorType>{}(data._type);
  for (auto & arg : data._args)
  {
    arg.apply(*this);
    h = (h << 1) ^ _hash;
  }
  setHash(node, h);
}

template <>
void
Hash<Real>::operator()(Node<Real> & node, UnaryFunctionData<Real> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  data._args[0].apply(*this);
  setHash(node, salt ^ std::hash<UnaryFunctionType>{}(data._type) ^ (_hash << 1));
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, BinaryFunctionData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  data._args[0].apply(*this);
  const auto hashA = _hash << 1;
  data._args[1].apply(*this);
  const auto hashB = _hash << 2;
  setHash(node, salt ^ std::hash<BinaryFunctionType>{}(data._type) ^ hashA ^ hashB);
}

template <>
void
Hash<Real>::operator()(Node<Real> & node, RealNumberData<Real> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  setHash(node, salt ^ std::hash<Real>{}(data._value));
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, RealReferenceData<T> & data)
{
  setHash(node, std::hash<const void *>{}(&data._ref));
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, RealArrayReferenceData<T> & data)
{
  fatalError("Not implemented yet");
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, LocalVariableData<T> & data)
{
  fatalError("Not implemented");
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, ConditionalData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  data._args[0].apply(*this);
  const auto hashA = _hash << 1;
  data._args[1].apply(*this);
  const auto hashB = _hash << 2;
  data._args[2].apply(*this);
  const auto hashC = _hash << 3;
  setHash(node, salt ^ hashA ^ hashB ^ hashC);
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, IntegerPowerData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  data._arg.apply(*this);
  setHash(node, salt ^ _hash ^ (std::hash<int>{}(data._exponent) << 1));
}

template <typename T>
void
Hash<T>::setHash(Node<T> & node, std::size_t h)
{
  _hash = h;
  _hash_map.emplace(h, &node);
}

template class Hash<Real>;

} // namespace SymbolicMath
<commit_msg>add missing header<commit_after>///
/// SymbolicMath toolkit
/// (c) 2017-2020 by Daniel Schwen
///

#include "SMTransformHash.h"
#include "SMFunction.h"

#include <functional>

namespace SymbolicMath
{

template <typename T>
Hash<T>::Hash(Function<T> & fb) : Transform<T>(fb)
{
  apply();
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, SymbolData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  setHash(node, salt ^ std::hash<std::string>{}(data._name));
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, UnaryOperatorData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  data._args[0].apply(*this);
  setHash(node, salt ^ std::hash<UnaryOperatorType>{}(data._type) ^ (_hash << 1));
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, BinaryOperatorData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  data._args[0].apply(*this);
  const auto hashA = _hash << 1;
  data._args[1].apply(*this);
  const auto hashB = _hash << 2;
  setHash(node, salt ^ std::hash<BinaryOperatorType>{}(data._type) ^ hashA ^ hashB);
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, MultinaryOperatorData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  auto h = salt ^ std::hash<MultinaryOperatorType>{}(data._type);
  for (auto & arg : data._args)
  {
    arg.apply(*this);
    h = (h << 1) ^ _hash;
  }
  setHash(node, h);
}

template <>
void
Hash<Real>::operator()(Node<Real> & node, UnaryFunctionData<Real> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  data._args[0].apply(*this);
  setHash(node, salt ^ std::hash<UnaryFunctionType>{}(data._type) ^ (_hash << 1));
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, BinaryFunctionData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  data._args[0].apply(*this);
  const auto hashA = _hash << 1;
  data._args[1].apply(*this);
  const auto hashB = _hash << 2;
  setHash(node, salt ^ std::hash<BinaryFunctionType>{}(data._type) ^ hashA ^ hashB);
}

template <>
void
Hash<Real>::operator()(Node<Real> & node, RealNumberData<Real> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  setHash(node, salt ^ std::hash<Real>{}(data._value));
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, RealReferenceData<T> & data)
{
  setHash(node, std::hash<const void *>{}(&data._ref));
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, RealArrayReferenceData<T> & data)
{
  fatalError("Not implemented yet");
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, LocalVariableData<T> & data)
{
  fatalError("Not implemented");
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, ConditionalData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  data._args[0].apply(*this);
  const auto hashA = _hash << 1;
  data._args[1].apply(*this);
  const auto hashB = _hash << 2;
  data._args[2].apply(*this);
  const auto hashC = _hash << 3;
  setHash(node, salt ^ hashA ^ hashB ^ hashC);
}

template <typename T>
void
Hash<T>::operator()(Node<T> & node, IntegerPowerData<T> & data)
{
  static const std::size_t salt = std::hash<const void *>{}(reinterpret_cast<const void *>(&salt));

  data._arg.apply(*this);
  setHash(node, salt ^ _hash ^ (std::hash<int>{}(data._exponent) << 1));
}

template <typename T>
void
Hash<T>::setHash(Node<T> & node, std::size_t h)
{
  _hash = h;
  _hash_map.emplace(h, &node);
}

template class Hash<Real>;

} // namespace SymbolicMath
<|endoftext|>


<commit_before><commit_msg>fixed typo<commit_after><|endoftext|>


<commit_before>
/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/bind.hpp>
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_timer(ios)
#ifndef NDEBUG
		, m_in_timeout_function(false)
#endif
	{}

	bool connection_queue::free_slots() const
	{ return m_num_connecting < m_half_open_limit || m_half_open_limit <= 0; }

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		m_queue.push_back(entry());
		entry& e = m_queue.back();
		e.on_connect = on_connect;
		e.on_timeout = on_timeout;
		e.ticket = m_next_ticket;
		e.timeout = timeout;
		++m_next_ticket;
		try_connect();
	}

	void connection_queue::done(int ticket)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);
		try_connect();
	}

	void connection_queue::close()
	{
		m_timer.cancel();
	}

	void connection_queue::limit(int limit)
	{ m_half_open_limit = limit; }

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifndef NDEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect()
	{
		INVARIANT_CHECK;

		if (!free_slots())
			return;

		if (m_queue.empty())
		{
			m_timer.cancel();
			return;
		}

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now() + i->timeout;
			if (m_num_connecting == 0)
			{
				m_timer.expires_at(expire);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			entry& ent = *i;
			++i;
			try { ent.on_connect(ent.ticket); } catch (std::exception&) {}

			if (!free_slots()) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}
	}

#ifndef NDEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(asio::error_code const& e)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;
#ifndef NDEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == asio::error::operation_aborted);
		if (e) return;

		ptime next_expire = max_time();
		ptime now = time_now();
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		// we don't want to call the timeout callback while we're locked
		// since that is a recepie for dead-locks
		l.unlock();

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			try { i->on_timeout(); } catch (std::exception&) {}
		}

		l.lock();

		if (next_expire < max_time())
		{
			m_timer.expires_at(next_expire);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
		}
		try_connect();
	}

}

<commit_msg>made connection queue build without exception support<commit_after>
/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/bind.hpp>
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_timer(ios)
#ifndef NDEBUG
		, m_in_timeout_function(false)
#endif
	{}

	bool connection_queue::free_slots() const
	{ return m_num_connecting < m_half_open_limit || m_half_open_limit <= 0; }

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		m_queue.push_back(entry());
		entry& e = m_queue.back();
		e.on_connect = on_connect;
		e.on_timeout = on_timeout;
		e.ticket = m_next_ticket;
		e.timeout = timeout;
		++m_next_ticket;
		try_connect();
	}

	void connection_queue::done(int ticket)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);
		try_connect();
	}

	void connection_queue::close()
	{
		asio::error_code ec;
		m_timer.cancel(ec);
	}

	void connection_queue::limit(int limit)
	{ m_half_open_limit = limit; }

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifndef NDEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect()
	{
		INVARIANT_CHECK;

		if (!free_slots())
			return;

		if (m_queue.empty())
		{
			asio::error_code ec;
			m_timer.cancel(ec);
			return;
		}

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now() + i->timeout;
			if (m_num_connecting == 0)
			{
				asio::error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			entry& ent = *i;
			++i;
#ifndef BOOST_NO_EXCEPTIONS
			try {
#endif
				ent.on_connect(ent.ticket);
#ifndef BOOST_NO_EXCEPTIONS
			} catch (std::exception&) {}
#endif

			if (!free_slots()) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}
	}

#ifndef NDEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(asio::error_code const& e)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;
#ifndef NDEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == asio::error::operation_aborted);
		if (e) return;

		ptime next_expire = max_time();
		ptime now = time_now();
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		// we don't want to call the timeout callback while we're locked
		// since that is a recepie for dead-locks
		l.unlock();

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			try { i->on_timeout(); } catch (std::exception&) {}
		}

		l.lock();

		if (next_expire < max_time())
		{
			asio::error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
		}
		try_connect();
	}

}

<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/bind.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/error.hpp"

#if defined TORRENT_ASIO_DEBUGGING
#include "libtorrent/debug.hpp"
#endif

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_timer(ios)
#ifdef TORRENT_DEBUG
		, m_in_timeout_function(false)
#endif
	{
#ifdef TORRENT_CONNECTION_LOGGING
		m_log.open("connection_queue.log");
#endif
	}

	int connection_queue::free_slots() const
	{
		TORRENT_ASSERT(is_single_thread());
		return m_half_open_limit == 0 ? (std::numeric_limits<int>::max)()
			: m_half_open_limit - m_queue.size();
	}

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout, int priority)
	{
		TORRENT_ASSERT(is_single_thread());

		INVARIANT_CHECK;

		TORRENT_ASSERT(priority >= 0);
		TORRENT_ASSERT(priority < 3);

		entry* e = 0;

		switch (priority)
		{
			case 0:
				m_queue.push_back(entry());
				e = &m_queue.back();
				break;
			case 1:
			case 2:
				m_queue.push_front(entry());
				e = &m_queue.front();
				break;
			default: return;
		}

		e->priority = priority;
		e->on_connect = on_connect;
		e->on_timeout = on_timeout;
		e->ticket = m_next_ticket;
		e->timeout = timeout;
		++m_next_ticket;

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::done(int ticket)
	{
		TORRENT_ASSERT(is_single_thread());

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::close()
	{
		error_code ec;
		TORRENT_ASSERT(is_single_thread());
		if (m_num_connecting == 0) m_timer.cancel(ec);

		std::list<entry> tmp;
		tmp.swap(m_queue);
		m_num_connecting = 0;

		while (!tmp.empty())
		{
			entry& e = tmp.front();
			if (e.priority > 1)
			{
				if (e.connecting) ++m_num_connecting;
				m_queue.push_back(e);
				tmp.pop_front();
				continue;
			}
			TORRENT_TRY {
				e.on_timeout();
			} TORRENT_CATCH(std::exception&) {}
			tmp.pop_front();
		}
	}

	void connection_queue::limit(int limit)
	{
		TORRENT_ASSERT(limit >= 0);
		m_half_open_limit = limit;
	}

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifdef TORRENT_DEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
			else TORRENT_ASSERT(i->expires == max_time());
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect()
	{
		TORRENT_ASSERT(is_single_thread());
		INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
		m_log << log_time() << " " << free_slots() << std::endl;
#endif

		if (m_num_connecting >= m_half_open_limit
			&& m_half_open_limit > 0) return;

		if (m_queue.empty())
		{
			TORRENT_ASSERT(m_num_connecting == 0);
			error_code ec;
			m_timer.cancel(ec);
			return;
		}

		// all entries are connecting, no need to look for new ones
		if (m_queue.size() == m_num_connecting)
			return;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);

		std::list<entry> to_connect;

		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now_hires() + i->timeout;
			if (m_num_connecting == 0)
			{
#if defined TORRENT_ASIO_DEBUGGING
				add_outstanding_async("connection_queue::on_timeout");
#endif
				error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			to_connect.push_back(*i);

#ifdef TORRENT_CONNECTION_LOGGING
			m_log << log_time() << " " << free_slots() << std::endl;
#endif

			if (m_num_connecting >= m_half_open_limit
				&& m_half_open_limit > 0) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}

		while (!to_connect.empty())
		{
			entry& ent = to_connect.front();
			TORRENT_ASSERT(m_num_connecting > 0);
#if defined TORRENT_ASIO_DEBUGGING
			TORRENT_ASSERT(has_outstanding_async("connection_queue::on_timeout"));
#endif
			TORRENT_TRY {
				ent.on_connect(ent.ticket);
			} TORRENT_CATCH(std::exception&) {}
			to_connect.pop_front();
		}
	}

#ifdef TORRENT_DEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(error_code const& e)
	{
#if defined TORRENT_ASIO_DEBUGGING
		complete_async("connection_queue::on_timeout");
#endif

		INVARIANT_CHECK;
#ifdef TORRENT_DEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == error::operation_aborted);
		if (e && m_num_connecting == 0)
			return;

		ptime next_expire = max_time();
		ptime now = time_now_hires() + milliseconds(100);
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->connecting && i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			TORRENT_ASSERT(i->connecting);
			TORRENT_ASSERT(i->ticket != -1);
			TORRENT_TRY {
				i->on_timeout();
			} TORRENT_CATCH(std::exception&) {}
		}

		if (next_expire < max_time())
		{
#if defined TORRENT_ASIO_DEBUGGING
			add_outstanding_async("connection_queue::on_timeout");
#endif
			error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
		}
		try_connect();
	}

	void connection_queue::on_try_connect()
	{
		try_connect();
	}
}

<commit_msg>revert previous connection_queue change and one more optimization<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/bind.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/error.hpp"

#if defined TORRENT_ASIO_DEBUGGING
#include "libtorrent/debug.hpp"
#endif

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_timer(ios)
#ifdef TORRENT_DEBUG
		, m_in_timeout_function(false)
#endif
	{
#ifdef TORRENT_CONNECTION_LOGGING
		m_log.open("connection_queue.log");
#endif
	}

	int connection_queue::free_slots() const
	{
		TORRENT_ASSERT(is_single_thread());
		return m_half_open_limit == 0 ? (std::numeric_limits<int>::max)()
			: m_half_open_limit - m_queue.size();
	}

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout, int priority)
	{
		TORRENT_ASSERT(is_single_thread());

		INVARIANT_CHECK;

		TORRENT_ASSERT(priority >= 0);
		TORRENT_ASSERT(priority < 3);

		entry* e = 0;

		switch (priority)
		{
			case 0:
				m_queue.push_back(entry());
				e = &m_queue.back();
				break;
			case 1:
			case 2:
				m_queue.push_front(entry());
				e = &m_queue.front();
				break;
			default: return;
		}

		e->priority = priority;
		e->on_connect = on_connect;
		e->on_timeout = on_timeout;
		e->ticket = m_next_ticket;
		e->timeout = timeout;
		++m_next_ticket;

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::done(int ticket)
	{
		TORRENT_ASSERT(is_single_thread());

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::close()
	{
		error_code ec;
		TORRENT_ASSERT(is_single_thread());
		if (m_num_connecting == 0) m_timer.cancel(ec);

		std::list<entry> tmp;
		tmp.swap(m_queue);
		m_num_connecting = 0;

		while (!tmp.empty())
		{
			entry& e = tmp.front();
			if (e.priority > 1)
			{
				if (e.connecting) ++m_num_connecting;
				m_queue.push_back(e);
				tmp.pop_front();
				continue;
			}
			TORRENT_TRY {
				e.on_timeout();
			} TORRENT_CATCH(std::exception&) {}
			tmp.pop_front();
		}
	}

	void connection_queue::limit(int limit)
	{
		TORRENT_ASSERT(limit >= 0);
		m_half_open_limit = limit;
	}

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifdef TORRENT_DEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
			else TORRENT_ASSERT(i->expires == max_time());
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect()
	{
		TORRENT_ASSERT(is_single_thread());
		INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
		m_log << log_time() << " " << free_slots() << std::endl;
#endif

		if (m_num_connecting >= m_half_open_limit
			&& m_half_open_limit > 0) return;

		if (m_queue.empty())
		{
			TORRENT_ASSERT(m_num_connecting == 0);
			error_code ec;
			m_timer.cancel(ec);
			return;
		}

		// all entries are connecting, no need to look for new ones
		if (m_queue.size() == m_num_connecting)
			return;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);

		std::list<entry> to_connect;

		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now_hires() + i->timeout;
			if (m_num_connecting == 0)
			{
#if defined TORRENT_ASIO_DEBUGGING
				add_outstanding_async("connection_queue::on_timeout");
#endif
				error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			to_connect.push_back(*i);

#ifdef TORRENT_CONNECTION_LOGGING
			m_log << log_time() << " " << free_slots() << std::endl;
#endif

			if (m_num_connecting >= m_half_open_limit
				&& m_half_open_limit > 0) break;
			if (m_num_connecting == m_queue.size()) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}

		while (!to_connect.empty())
		{
			entry& ent = to_connect.front();
			TORRENT_ASSERT(m_num_connecting > 0);
#if defined TORRENT_ASIO_DEBUGGING
			TORRENT_ASSERT(has_outstanding_async("connection_queue::on_timeout"));
#endif
			TORRENT_TRY {
				ent.on_connect(ent.ticket);
			} TORRENT_CATCH(std::exception&) {}
			to_connect.pop_front();
		}
	}

#ifdef TORRENT_DEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(error_code const& e)
	{
#if defined TORRENT_ASIO_DEBUGGING
		complete_async("connection_queue::on_timeout");
#endif

		INVARIANT_CHECK;
#ifdef TORRENT_DEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == error::operation_aborted);
		if (e) return;

		ptime next_expire = max_time();
		ptime now = time_now_hires() + milliseconds(100);
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->connecting && i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			TORRENT_ASSERT(i->connecting);
			TORRENT_ASSERT(i->ticket != -1);
			TORRENT_TRY {
				i->on_timeout();
			} TORRENT_CATCH(std::exception&) {}
		}

		if (next_expire < max_time())
		{
#if defined TORRENT_ASIO_DEBUGGING
			add_outstanding_async("connection_queue::on_timeout");
#endif
			error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
		}
		try_connect();
	}

	void connection_queue::on_try_connect()
	{
		try_connect();
	}
}

<|endoftext|>