text:
/*

Copyright (c) 2008, 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 "libtorrent/piece_picker.hpp"
#include "libtorrent/torrent_peer.hpp"
#include "libtorrent/bitfield.hpp"
#include "libtorrent/performance_counters.hpp"
#include "libtorrent/random.hpp"

#include "libtorrent/aux_/disable_warnings_push.hpp"

#include <boost/shared_ptr.hpp>

#include "libtorrent/aux_/disable_warnings_pop.hpp"

#include <functional>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <iostream>

#include "test.hpp"

using namespace libtorrent;
using namespace std::placeholders;

const int blocks_per_piece = 4;

bitfield string2vec(char const* have_str)
{
	const int num_pieces = int(strlen(have_str));
	bitfield have(num_pieces, false);
	for (int i = 0; i < num_pieces; ++i)
		if (have_str[i] != ' ') have.set_bit(i);
	return have;
}

ipv4_peer* tmp_peer = 0;

tcp::endpoint endp;
ipv4_peer tmp0(endp, false, 0);
ipv4_peer tmp1(endp, false, 0);
ipv4_peer tmp2(endp, false, 0);
ipv4_peer tmp3(endp, false, 0);
ipv4_peer tmp4(endp, false, 0);
ipv4_peer tmp5(endp, false, 0);
ipv4_peer tmp6(endp, false, 0);
ipv4_peer tmp7(endp, false, 0);
ipv4_peer tmp8(endp, false, 0);
ipv4_peer tmp9(endp, false, 0);
ipv4_peer peer_struct(endp, true, 0);

const std::vector<int> empty_vector;

// availability is a string where each character is the
// availability of that piece, '1', '2' etc.
// have_str is a string where each character represents a
// piece, ' ' means we don't have the piece and any other
// character means we have it
boost::shared_ptr<piece_picker> setup_picker(
	char const* availability
	, char const* have_str
	, char const* priority
	, char const* partial)
{
	const int num_pieces = int(strlen(availability));
	TORRENT_ASSERT(int(strlen(have_str)) == num_pieces);

	boost::shared_ptr<piece_picker> p(new piece_picker);
	p->init(blocks_per_piece, blocks_per_piece, num_pieces);

	for (int i = 0; i < num_pieces; ++i)
	{
		const int avail = availability[i] - '0';
		assert(avail >= 0);

		static const torrent_peer* peers[10] = { &tmp0, &tmp1, &tmp2
			, &tmp3, &tmp4, &tmp5, &tmp6, &tmp7, &tmp8, &tmp9 };
		TORRENT_ASSERT(avail < 10);
		for (int j = 0; j < avail; ++j) p->inc_refcount(i, peers[j]);
	}

	bitfield have = string2vec(have_str);

	for (int i = 0; i < num_pieces; ++i)
	{
		if (partial[i] == 0) break;

		if (partial[i] == ' ') continue;

		int blocks = 0;
		if (partial[i] >= '0' && partial[i] <= '9')
			blocks = partial[i] - '0';
		else
			blocks = partial[i] - 'a' + 10;

		int counter = 0;
		for (int j = 0; j < 4; ++j)
		{
			TEST_CHECK(!p->is_finished(piece_block(i, j)));
			if ((blocks & (1 << j)) == 0) continue;
			++counter;
			bool ret = p->mark_as_downloading(piece_block(i, j), tmp_peer);
			TEST_CHECK(ret == true);
			TEST_CHECK(p->is_requested(piece_block(i, j)) == ((blocks & (1 << j)) != 0));
			p->mark_as_writing(piece_block(i, j), tmp_peer);
			TEST_CHECK(!p->is_finished(piece_block(i, j)));
			// trying to mark a block as requested after it has been completed
			// should fail (return false)
			ret = p->mark_as_downloading(piece_block(i, j), tmp_peer);
			TEST_CHECK(ret == false);
			p->mark_as_finished(piece_block(i, j), tmp_peer);

			TEST_CHECK(p->is_downloaded(piece_block(i, j)) == ((blocks & (1 << j)) != 0));
			TEST_CHECK(p->is_finished(piece_block(i, j)) == ((blocks & (1 << j)) != 0));
		}

		piece_picker::downloading_piece st;
		p->piece_info(i, st);
		TEST_EQUAL(int(st.writing), 0);
		TEST_EQUAL(int(st.requested), 0);
		TEST_EQUAL(int(st.index),  i);

		TEST_EQUAL(st.finished, counter);
		TEST_EQUAL(st.finished + st.requested + st.writing, counter);

		TEST_CHECK(p->is_piece_finished(i) == (counter == 4));
	}

	for (int i = 0; i < num_pieces; ++i)
	{
		if (priority[i] == 0) break;
		const int prio = priority[i] - '0';
		assert(prio >= 0);
		p->set_piece_priority(i, prio);

		TEST_CHECK(p->piece_priority(i) == prio);
	}

	for (int i = 0; i < num_pieces; ++i)
	{
		if (!have[i]) continue;
		p->we_have(i);
		for (int j = 0; j < blocks_per_piece; ++j)
			TEST_CHECK(p->is_finished(piece_block(i, j)));
	}

	std::vector<int> availability_vec;
	p->get_availability(availability_vec);
	for (int i = 0; i < num_pieces; ++i)
	{
		const int avail = availability[i] - '0';
		assert(avail >= 0);
		TEST_CHECK(avail == availability_vec[i]);
	}

#if defined TORRENT_DEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
	p->check_invariant();
#endif
	return p;
}

bool verify_pick(boost::shared_ptr<piece_picker> p
	, std::vector<piece_block> const& picked, bool allow_multi_blocks = false)
{
#if defined TORRENT_DEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
	p->check_invariant();
#endif
	if (!allow_multi_blocks)
	{
		for (std::vector<piece_block>::const_iterator i = picked.begin()
			, end(picked.end()); i != end; ++i)
		{
			if (p->num_peers(*i) > 0) return false;
		}
	}

	// make sure there are no duplicated
	std::set<piece_block> blocks;
	std::copy(picked.begin(), picked.end()
		, std::insert_iterator<std::set<piece_block> >(blocks, blocks.end()));
	std::cerr << " verify: " << picked.size() << " " << blocks.size() << std::endl;
	return picked.size() == blocks.size();
}

void print_availability(boost::shared_ptr<piece_picker> const& p)
{
	std::vector<int> avail;
	p->get_availability(avail);
	std::printf("[ ");
	for (std::vector<int>::iterator i = avail.begin()
		, end(avail.end()); i != end; ++i)
	{
		std::printf("%d ", *i);
	}
	std::printf("]\n");
}

bool verify_availability(boost::shared_ptr<piece_picker> const& p, char const* a)
{
	std::vector<int> avail;
	p->get_availability(avail);
	for (std::vector<int>::iterator i = avail.begin()
		, end(avail.end()); i != end; ++i, ++a)
	{
		if (*a - '0' != *i) return false;
	}
	return true;
}

void print_pick(std::vector<piece_block> const& picked)
{
	for (int i = 0; i < int(picked.size()); ++i)
	{
		std::cout << "(" << picked[i].piece_index << ", " << picked[i].block_index << ") ";
	}
	std::cout << std::endl;
}

void print_title(char const* name)
{
	std::cerr << "==== " << name << " ====\n";
}

std::vector<piece_block> pick_pieces(boost::shared_ptr<piece_picker> const& p
	, char const* availability
	, int num_blocks
	, int prefer_contiguous_blocks
	, torrent_peer* peer_struct
	, int options = piece_picker::rarest_first
	, std::vector<int> const& suggested_pieces = empty_vector)
{
	std::vector<piece_block> picked;
	counters pc;
	p->pick_pieces(string2vec(availability), picked
		, num_blocks, prefer_contiguous_blocks, peer_struct
		, options, suggested_pieces, 20, pc);
	print_pick(picked);
	TEST_CHECK(verify_pick(p, picked));
	return picked;
}

int test_pick(boost::shared_ptr<piece_picker> const& p
	, int options = piece_picker::rarest_first)
{
	const std::vector<int> empty_vector;
	std::vector<piece_block> picked = pick_pieces(p, "*******", 1, 0, 0
		, options, empty_vector);
	if (picked.empty()) return -1;
	return picked[0].piece_index;
}

// TODO: 2 split this up into smaller tests (where we print_title)
TORRENT_TEST(piece_picker)
{
	tcp::endpoint endp;
	piece_picker::downloading_piece st;
#if TORRENT_USE_ASSERTS
	tmp0.in_use = true;
	tmp1.in_use = true;
	tmp2.in_use = true;
	tmp3.in_use = true;
	tmp4.in_use = true;
	tmp5.in_use = true;
	tmp6.in_use = true;
	tmp7.in_use = true;
	tmp8.in_use = true;
	tmp9.in_use = true;
	peer_struct.in_use = true;
#endif
	tmp_peer = &tmp1;
	std::vector<piece_block> picked;
	boost::shared_ptr<piece_picker> p;
	const int options = piece_picker::rarest_first;
	std::pair<int, int> dc;
	counters pc;

	print_title("test piece_block");

	TEST_CHECK(piece_block(0, 0) != piece_block(0, 1));
	TEST_CHECK(piece_block(0, 0) != piece_block(1, 0));
	TEST_CHECK(!(piece_block(0, 0) != piece_block(0, 0)));

	TEST_CHECK(!(piece_block(0, 0) == piece_block(0, 1)));
	TEST_CHECK(!(piece_block(0, 0) == piece_block(1, 0)));
	TEST_CHECK(piece_block(0, 0) == piece_block(0, 0));

	TEST_CHECK(!(piece_block(0, 1) < piece_block(0, 0)));
	TEST_CHECK(!(piece_block(1, 0) < piece_block(0, 0)));
	TEST_CHECK(piece_block(0, 0) < piece_block(0, 1));
	TEST_CHECK(piece_block(0, 0) < piece_block(1, 0));
	TEST_CHECK(!(piece_block(0, 0) < piece_block(0, 0)));
	TEST_CHECK(!(piece_block(1, 0) < piece_block(1, 0)));
	TEST_CHECK(!(piece_block(0, 1) < piece_block(0, 1)));

// ========================================================

	// test abort_download
	print_title("test abort_download");

	p = setup_picker("1111111", "       ", "7110000", "");
	picked = pick_pieces(p, "*******", blocks_per_piece, 0, tmp_peer
		, options, empty_vector);
	TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
	TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) != picked.end());

	p->abort_download(piece_block(0,0), tmp_peer);
	picked = pick_pieces(p, "*******", blocks_per_piece, 0, tmp_peer
		, options, empty_vector);
	TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
	TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) != picked.end());

	p->mark_as_downloading(piece_block(0,0), &tmp1);
	picked = pick_pieces(p, "*******", blocks_per_piece, 0, tmp_peer
		, options, empty_vector);
	TEST_CHECK(p->is_requested(piece_block(0, 0)) == true);
	TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) == picked.end());

	p->abort_download(piece_block(0,0), tmp_peer);
	picked = pick_pieces(p, "*******", blocks_per_piece, 0, tmp_peer
		, options, empty_vector);
	TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
	TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) != picked.end());

	p->mark_as_downloading(piece_block(0,0), &tmp1);
	p->mark_as_downloading(piece_block(0,1), &tmp1);
	p->abort_download(piece_block(0,0), tmp_peer);
	picked = pick_pieces(p, "*******", blocks_per_piece, 0, tmp_peer
		, options, empty_vector);
	TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
	TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) != picked.end());

	p->mark_as_downloading(piece_block(0,0), &tmp1);
	p->mark_as_writing(piece_block(0,0), &tmp1);
	p->write_failed(piece_block(0,0));
	picked = pick_pieces(p, "*******", blocks_per_piece, 0, tmp_peer
		, options, empty_vector);
	TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(1,0)) != picked.end()
		|| std::find(picked.begin(), picked.end(), piece_block(2,0)) != picked.end());
	TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) == picked.end());
	p->restore_piece(0);
	picked = pick_pieces(p, "*******", blocks_per_piece, 0, tmp_peer
		, options, empty_vector);
	TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
	TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) != picked.end());

	p->mark_as_downloading(piece_block(0,0), &tmp1);
	p->mark_as_writing(piece_block(0,0), &tmp1);
	p->mark_as_finished(piece_block(0,0), &tmp1);
	p->abort_download(piece_block(0,0), tmp_peer);
	picked = pick_pieces(p, "*******", blocks_per_piece, 0, tmp_peer
		, options, empty_vector);
	TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
	TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) == picked.end());

// ========================================================

	print_title("test abort_download");

	p = setup_picker("1111111", "       ", "7110000", "");
	p->mark_as_downloading(piece_block(0,0), &tmp1);
	p->mark_as_finished(piece_block(0,1), 0);
	p->piece_info(0, st);
	TEST_EQUAL(st.requested, 1);
	TEST_EQUAL(st.finished, 1);
	p->abort_download(piece_block(0,0), tmp_peer);
	p->piece_info(0, st);
	TEST_EQUAL(st.requested, 0);
	TEST_EQUAL(st.finished, 1);
	picked = pick_pieces(p, "*******", blocks_per_piece, 0, 0
		, options, empty_vector);
	TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
	TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) != picked.end());

// ========================================================

	print_title("test get_downloaders");

	p = setup_picker("1111111", "       ", "7110000", "");

	p->mark_as_downloading(piece_block(0, 2), &tmp1);
	p->mark_as_writing(piece_block(0, 2), &tmp1);
	p->abort_download(piece_block(0, 2), &tmp1);
	p->mark_as_downloading(piece_block(0, 2), &tmp2);
	p->mark_as_writing(piece_block(0, 2), &tmp2);

	std::vector<torrent_peer*> d;
	p->get_downloaders(d, 0);
	TEST_EQUAL(d.size(), 4);
	TEST_CHECK(d[0] == NULL);
	TEST_CHECK(d[1] == NULL);
	TEST_CHECK(d[2] == &tmp2);
	TEST_CHECK(d[3] == NULL);

	p->mark_as_downloading(piece_block(0, 3), &tmp1);
	p->abort_download(piece_block(0, 3), &tmp1);
	p->mark_as_downloading(piece_block(0, 3), &tmp2);
	p->mark_as_writing(piece_block(0, 3), &tmp2);

	p->get_downloaders(d, 0);

	TEST_EQUAL(d.size(), 4);
	TEST_CHECK(d[0] == NULL);
	TEST_CHECK(d[1] == NULL);
	TEST_CHECK(d[2] == &tmp2);
	TEST_CHECK(d[3] == &tmp2);

	// if we ask for downloaders for a piece that's not
	// curently being downloaded, we get zeroes back
	p->get_downloaders(d, 1);

	TEST_EQUAL(d.size(), 4);
	TEST_CHECK(d[0] == NULL);
	TEST_CHECK(d[1] == NULL);
	TEST_CHECK(d[2] == NULL);
	TEST_CHECK(d[3] == NULL);

// ========================================================

	p = setup_picker("2222", "    ", "", "");

	for (int i = 0; i < 4; ++i)
		for (int k = 0; k < blocks_per_piece; ++k)
			p->mark_as_downloading(piece_block(i, k), &tmp1);

	p->mark_as_downloading(piece_block(0, 0), &tmp2);

	std::fprintf(stderr, "num_peers: %d\n", p->num_peers(piece_block(0, 0)));
	TEST_EQUAL(p->num_peers(piece_block(0, 0)), 2);

	p->abort_download(piece_block(0, 0), &tmp1);

	std::fprintf(stderr, "num_peers: %d\n", p->num_peers(piece_block(0, 0)));
	TEST_EQUAL(p->num_peers(piece_block(0, 0)), 1);

// ========================================================

	// make sure the block that is picked is from piece 1, since it
	// it is the piece with the lowest availability
	print_title("test pick lowest availability");
	p = setup_picker("2223333", "* * *  ", "", "");
	TEST_CHECK(test_pick(p) == 1);

// ========================================================

	// make sure pieces with equal priority and availability
	// are picked at random
	print_title("test random pick at same priority");
	std::map<int, int> random_prio_pieces;
	for (int i = 0; i < 100; ++i)
	{
		p = setup_picker("1111112", "       ", "", "");
		++random_prio_pieces[test_pick(p)];
	}
	TEST_CHECK(random_prio_pieces.size() == 6);
	for (std::map<int, int>::iterator i = random_prio_pieces.begin()
		, end(random_prio_pieces.end()); i != end; ++i)
		std::cout << i->first << ": " << i->second << " ";
	std::cout << std::endl;

// ========================================================

	// make sure the block that is picked is from piece 5, since it
	// has the highest priority among the available pieces
	print_title("test pick highest priority");
	p = setup_picker("1111111", "       ", "1111121", "");
	TEST_CHECK(test_pick(p) == 5);

	p = setup_picker("1111111", "       ", "1171121", "");
	TEST_CHECK(test_pick(p) == 2);

	p = setup_picker("1111111", "       ", "1131521", "");
	TEST_CHECK(test_pick(p) == 4);

// ========================================================

	print_title("test reverse rarest first");
	p = setup_picker("4179253", "       ", "", "");
	picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, &peer_struct
		, piece_picker::rarest_first | piece_picker::reverse, empty_vector);
	int expected_common_pieces[] = {3, 2, 5, 0, 6, 4, 1};
	for (int i = 0; i < int(picked.size()); ++i)
		TEST_CHECK(picked[i] == piece_block(expected_common_pieces[i / blocks_per_piece], i % blocks_per_piece));

	// piece 3 should NOT be prioritized since it's a partial, and not
	// reversed. Reversed partials are considered reversed
	p = setup_picker("1122111", "       ", "3333333", "   1   ");
	TEST_CHECK(test_pick(p, piece_picker::rarest_first | piece_picker::reverse) == 2);

// ========================================================

	// make sure the 4 blocks are picked from the same piece if
	// whole pieces are preferred. Priority and availability is more
	// important. Piece 1 has the lowest availability even though
	// it is not a whole piece
	print_title("test pick whole pieces");
	p = setup_picker("2212222", "       ", "1111111", "1023460");
	picked = pick_pieces(p, "****** ", 1, blocks_per_piece
		, &peer_struct, options, empty_vector);
	TEST_EQUAL(int(picked.size()), 3);
	for (int i = 0; i < blocks_per_piece && i < int(picked.size()); ++i)
		TEST_EQUAL(picked[i].piece_index, 2);

	p = setup_picker("1111111", "       ", "1111111", "");
	picked = pick_pieces(p, "****** ", 1, blocks_per_piece
		, &peer_struct, options, empty_vector);
	TEST_EQUAL(int(picked.size()), blocks_per_piece);
	for (int i = 0; i < blocks_per_piece && i < int(picked.size()); ++i)
		TEST_EQUAL(picked[i].block_index, i);

	p = setup_picker("2221222", "       ", "", "");
	picked = pick_pieces(p, "*******", 1, 7 * blocks_per_piece
		, &peer_struct, options, empty_vector);
	TEST_EQUAL(int(picked.size()), 7 * blocks_per_piece);
	for (int i = 0; i < int(picked.size()); ++i)
		TEST_CHECK(picked[i] == piece_block(i / blocks_per_piece, i % blocks_per_piece));

// ========================================================

	// test the distributed copies function. It should include ourself
	// in the availability. i.e. piece 0 has availability 2.
	// there are 2 pieces with availability 2 and 5 with availability 3
	print_title("test distributed copies");
	p = setup_picker("1233333", "*      ", "", "");
	dc = p->distributed_copies();
	TEST_CHECK(dc == std::make_pair(2, 5000 / 7));

// ========================================================

	// make sure filtered pieces are ignored
	print_title("test filtered pieces");
	p = setup_picker("1111111", "       ", "0010000", "");
	TEST_CHECK(test_pick(p, piece_picker::rarest_first) == 2);
	TEST_CHECK(test_pick(p, piece_picker::rarest_first | piece_picker::reverse) == 2);
	TEST_CHECK(test_pick(p, piece_picker::sequential) == 2);
	TEST_CHECK(test_pick(p, piece_picker::sequential | piece_picker::reverse) == 2);

// ========================================================

	// make sure we_dont_have works
	print_title("test we_dont_have");
	p = setup_picker("1111111", "*******", "0100000", "");
	TEST_CHECK(p->have_piece(1));
	TEST_CHECK(p->have_piece(2));
	p->we_dont_have(1);
	p->we_dont_have(2);
	TEST_CHECK(!p->have_piece(1));
	TEST_CHECK(!p->have_piece(2));
	picked = pick_pieces(p, "*** ** ", 1, 0, 0, options, empty_vector);
	TEST_CHECK(int(picked.size()) > 0);
	TEST_CHECK(picked.front().piece_index == 1);

// ========================================================

	// make sure we can split m_seed when removing a refcount
	print_title("test dec_refcount split seed");
	p = setup_picker("0000000", "       ", "0000000", "");
	p->inc_refcount_all(0);

	std::vector<int> avail;
	p->get_availability(avail);
	TEST_EQUAL(avail.size(), 7);
	TEST_CHECK(avail[0] != 0);
	TEST_CHECK(avail[1] != 0);
	TEST_CHECK(avail[2] != 0);
	TEST_CHECK(avail[3] != 0);
	TEST_CHECK(avail[4] != 0);

	p->dec_refcount(3, 0);

	p->get_availability(avail);
	TEST_EQUAL(avail.size(), 7);

	TEST_CHECK(avail[0] != 0);
	TEST_CHECK(avail[1] != 0);
	TEST_CHECK(avail[2] != 0);
	TEST_CHECK(avail[3] == 0);
	TEST_CHECK(avail[4] != 0);

// ========================================================

	// make sure init preserves priorities
	print_title("test init");
	p = setup_picker("1111111", "       ", "1111111", "");

	TEST_CHECK(p->num_filtered() == 0);
	TEST_CHECK(p->num_have_filtered() == 0);
	TEST_CHECK(p->num_have() == 0);

	p->set_piece_priority(0, 0);
	TEST_CHECK(p->num_filtered() == 1);
	TEST_CHECK(p->num_have_filtered() == 0);
	TEST_CHECK(p->num_have() == 0);

	p->we_have(0);

	TEST_CHECK(p->num_filtered() == 0);
	TEST_CHECK(p->num_have_filtered() == 1);
	TEST_CHECK(p->num_have() == 1);

	p->init(blocks_per_piece, blocks_per_piece, blocks_per_piece * 7);
	TEST_CHECK(p->piece_priority(0) == 0);
	TEST_CHECK(p->num_filtered() == 1);
	TEST_CHECK(p->num_have_filtered() == 0);
	TEST_CHECK(p->num_have() == 0);

// ========================================================

	// make sure requested blocks aren't picked
	print_title("test don't pick requested blocks");
	p = setup_picker("1111111", "       ", "", "");
	picked = pick_pieces(p, "*******", 1, 0, 0, options, empty_vector);
	TEST_CHECK(int(picked.size()) > 0);
	piece_block first = picked.front();
	p->mark_as_downloading(picked.front(), &peer_struct);
	TEST_CHECK(p->num_peers(picked.front()) == 1);
	picked = pick_pieces(p, "*******", 1, 0, 0, options, empty_vector);
	TEST_CHECK(int(picked.size()) > 0);
	TEST_CHECK(picked.front() != first);

// ========================================================

	// make sure downloading pieces have higher priority
	print_title("test downloading piece priority");
	p = setup_picker("1111111", "       ", "", "");
	picked = pick_pieces(p, "*******", 1, 0, 0, options, empty_vector);
	TEST_CHECK(int(picked.size()) > 0);
	first = picked.front();
	p->mark_as_downloading(picked.front(), &peer_struct);
	TEST_CHECK(p->num_peers(picked.front()) == 1);
	picked = pick_pieces(p, "*******", 1, 0, 0, options, empty_vector);
	TEST_CHECK(int(picked.size()) > 0);
	TEST_CHECK(picked.front() != first);
	TEST_CHECK(picked.front().piece_index == first.piece_index);

// ========================================================

	// when we're prioritizing partial pieces, make sure to first pick the
	// rarest of them. The blocks in this test are:
	// 0: [    ] avail: 1
	// 1: [x   ] avail: 1
	// 2: [xx  ] avail: 1
	// 3: [xxx ] avail: 2
	// 4: [    ] avail: 1
	// 5: [    ] avail: 1
	// 6: [xxxx] avail: 1
	// piece 6 does not have any blocks left to pick, even though piece 3 only
	// has a single block left before it completes, it is less rare than piece
	// 2. Piece 2 is the best pick in this case.
	print_title("test partial piece order (rarest first)");
	p = setup_picker("1112111", "       ", "", "013700f");
	picked = pick_pieces(p, "*******", 1, 0, 0
		, options | piece_picker::prioritize_partials, empty_vector);
	TEST_CHECK(int(picked.size()) > 0);
	TEST_CHECK(picked.front() == piece_block(2, 2)
		|| picked.front() == piece_block(2, 3));

	// as a tie breaker, make sure downloading pieces closer to completion have
	// higher priority. piece 3 is only 1 block from being completed, and should
	// be picked

	print_title("test partial piece order (most complete)");
	p = setup_picker("1111111", "       ", "", "013700f");
	picked = pick_pieces(p, "*******", 1, 0, 0
		, options | piece_picker::prioritize_partials, empty_vector);
	TEST_CHECK(int(picked.size()) > 0);
	TEST_CHECK(picked.front() == piece_block(3, 3));

	// if we don't use rarest first when we prioritize partials, but instead use
	// sequential order, make sure we pick the right one

	print_title("test partial piece order (sequential)");
	p = setup_picker("1111111", "       ", "", "013700f");
	picked = pick_pieces(p, "*******", 1, 0, 0
		, piece_picker::sequential | piece_picker::prioritize_partials, empty_vector);
	TEST_CHECK(int(picked.size()) > 0);
	TEST_CHECK(picked.front() == piece_block(1, 1)
		|| picked.front() == piece_block(1, 2)
		|| picked.front() == piece_block(1, 3));

// ========================================================

	// make sure the random piece picker can still pick partial pieces
	print_title("test random picking (downloading piece)");
	p = setup_picker("1111111", "       ", "", "013700f");
	picked = pick_pieces(p, " ***  *", 1, 0, 0
		, 0, empty_vector);
	TEST_CHECK(int(picked.size()) > 0);
	TEST_CHECK(picked.front() == piece_block(1, 1)
		|| picked.front() == piece_block(2, 2)
		|| picked.front() == piece_block(3, 3));

	// make sure the random piece picker can still pick partial pieces
	// even when prefer_contiguous_blocks is set
	print_title("test random picking (downloading piece, prefer contiguous)");
	p = setup_picker("1111111", "       ", "", "013700f");
	picked = pick_pieces(p, " ***  *", 1, 4, 0
		, 0, empty_vector);
	TEST_CHECK(int(picked.size()) > 0);
	TEST_CHECK(picked.front() == piece_block(1, 1)
		|| picked.front() == piece_block(2, 2)
		|| picked.front() == piece_block(3, 3));

// ========================================================

	// test sequential download
	print_title("test sequential download");
	p = setup_picker("7654321", "       ", "", "");
	picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, 0
		, piece_picker::sequential, empty_vector);
	TEST_CHECK(int(picked.size()) == 7 * blocks_per_piece);
	for (int i = 0; i < int(picked.size()); ++i)
		TEST_CHECK(picked[i] == piece_block(i / blocks_per_piece, i % blocks_per_piece));

// ========================================================

	// test reverse sequential download
	print_title("test reverse sequential download");
	p = setup_picker("7654321", "       ", "", "");
	picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, 0
		, piece_picker::sequential | piece_picker::reverse, empty_vector);
	TEST_CHECK(int(picked.size()) == 7 * blocks_per_piece);
	for (int i = 0; i < int(picked.size()); ++i)
		TEST_CHECK(picked[i] == piece_block(6 - (i / blocks_per_piece), i % blocks_per_piece));

// ========================================================

	// test priority sequential download
	print_title("test priority sequential download");
	p = setup_picker("7654321", "       ", "1117071", "");
	picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, 0
		, piece_picker::sequential, empty_vector);

	// the piece with priority 0 was not picked, everything else should
	// be picked
	TEST_EQUAL(int(picked.size()), 6 * blocks_per_piece);

	// the first two pieces picked should be 3 and 5 since those have priority 7
	for (int i = 0; i < 2 * blocks_per_piece; ++i)
		TEST_CHECK(picked[i].piece_index == 3 || picked[i].piece_index == 5);

	int expected[] = {-1, -1, 0, 1, 2, 6};
	for (int i = 2 * blocks_per_piece; i < int(picked.size()); ++i)
		TEST_EQUAL(picked[i].piece_index, expected[i / blocks_per_piece]);

// ========================================================

	// sweep up, we_have()
	print_title("test cursors. sweep up, we_have");
	p = setup_picker("7654321", "       ", "", "");
	for (int i = 0; i < 7; ++i)
	{
		TEST_EQUAL(p->cursor(), i);
		TEST_EQUAL(p->reverse_cursor(), 7);
		p->we_have(i);
	}
	TEST_CHECK(p->is_finished());
	TEST_CHECK(p->is_seeding());
	TEST_EQUAL(p->cursor(), 7);
	TEST_EQUAL(p->reverse_cursor(), 0);

	// sweep up, set_piece_priority()
	print_title("test cursors. sweep up, set_piece_priority");
	p = setup_picker("7654321", "       ", "", "");
	for (int i = 0; i < 7; ++i)
	{
		TEST_EQUAL(p->cursor(), i);
		TEST_EQUAL(p->reverse_cursor(), 7);
		p->set_piece_priority(i, 0);
	}
	TEST_CHECK(p->is_finished());
	TEST_CHECK(!p->is_seeding());
	TEST_EQUAL(p->cursor(), 7);
	TEST_EQUAL(p->reverse_cursor(), 0);

	// sweep down, we_have()
	print_title("test cursors. sweep down, we_have");
	p = setup_picker("7654321", "       ", "", "");
	for (int i = 6; i >= 0; --i)
	{
		TEST_EQUAL(p->cursor(), 0);
		TEST_EQUAL(p->reverse_cursor(), i + 1);
		p->we_have(i);
	}
	TEST_CHECK(p->is_finished());
	TEST_CHECK(p->is_seeding());
	TEST_EQUAL(p->cursor(), 7);
	TEST_EQUAL(p->reverse_cursor(), 0);

	// sweep down, set_piece_priority()
	print_title("test cursors. sweep down, set_piece_priority");
	p = setup_picker("7654321", "       ", "", "");
	for (int i = 6; i >= 0; --i)
	{
		TEST_EQUAL(p->cursor(), 0);
		TEST_EQUAL(p->reverse_cursor(), i + 1);
		p->set_piece_priority(i, 0);
	}
	TEST_CHECK(p->is_finished());
	TEST_CHECK(!p->is_seeding());
	TEST_EQUAL(p->cursor(), 7);
	TEST_EQUAL(p->reverse_cursor(), 0);

	// sweep in, set_piece_priority()
	print_title("test cursors. sweep in, set_piece_priority");
	p = setup_picker("7654321", "       ", "", "");
	for (int left = 0, right = 6; left <= 3 && right >= 3; ++left, --right)
	{
		TEST_EQUAL(p->cursor(), left);
		TEST_EQUAL(p->reverse_cursor(), right + 1);
		p->set_piece_priority(left, 0);
		p->set_piece_priority(right, 0);
	}
	TEST_CHECK(p->is_finished());
	TEST_CHECK(!p->is_seeding());
	TEST_EQUAL(p->cursor(), 7);
	TEST_EQUAL(p->reverse_cursor(), 0);

	// sweep in, we_have()
	print_title("test cursors. sweep in, we_have");
	p = setup_picker("7654321", "       ", "", "");
	for (int left = 0, right = 6; left <= 3 && right >= 3; ++left, --right)
	{
		TEST_EQUAL(p->cursor(), left);
		TEST_EQUAL(p->reverse_cursor(), right + 1);
		p->we_have(left);
		p->we_have(right);
	}
	TEST_CHECK(p->is_finished());
	TEST_CHECK(p->is_seeding());
	TEST_EQUAL(p->cursor(), 7);
	TEST_EQUAL(p->reverse_cursor(), 0);

	print_title("test cursors. sweep up, we_dont_have");
	p = setup_picker("7654321", "*******", "", "");
	TEST_CHECK(p->is_finished());
	TEST_CHECK(p->is_seeding());
	TEST_EQUAL(p->cursor(), 7);
	TEST_EQUAL(p->reverse_cursor(), 0);
	for (int i = 0; i < 7; ++i)
	{
		p->we_dont_have(i);
		TEST_EQUAL(p->cursor(), 0);
		TEST_EQUAL(p->reverse_cursor(), i + 1);
	}
	TEST_CHECK(!p->is_finished());
	TEST_CHECK(!p->is_seeding());
	TEST_EQUAL(p->cursor(), 0);
	TEST_EQUAL(p->reverse_cursor(), 7);

	print_title("test cursors. sweep down, we_dont_have");
	p = setup_picker("7654321", "*******", "", "");
	TEST_CHECK(p->is_finished());
	TEST_CHECK(p->is_seeding());
	TEST_EQUAL(p->cursor(), 7);
	TEST_EQUAL(p->reverse_cursor(), 0);
	for (int i = 6; i >= 0; --i)
	{
		p->we_dont_have(i);
		TEST_EQUAL(p->cursor(), i);
		TEST_EQUAL(p->reverse_cursor(), 7);
	}
	TEST_CHECK(!p->is_finished());
	TEST_CHECK(!p->is_seeding());
	TEST_EQUAL(p->cursor(), 0);
	TEST_EQUAL(p->reverse_cursor(), 7);

	print_title("test cursors. sweep out, we_dont_have");
	p = setup_picker("7654321", "*******", "", "");
	TEST_CHECK(p->is_finished());
	TEST_CHECK(p->is_seeding());
	TEST_EQUAL(p->cursor(), 7);
	TEST_EQUAL(p->reverse_cursor(), 0);
	for (int left = 3, right = 3; left >= 0 && right < 7; --left, ++right)
	{
		p->we_dont_have(left);
		p->we_dont_have(right);
		TEST_EQUAL(p->cursor(), left);
		TEST_EQUAL(p->reverse_cursor(), right + 1);
	}
	TEST_CHECK(!p->is_finished());
	TEST_CHECK(!p->is_seeding());
	TEST_EQUAL(p->cursor(), 0);
	TEST_EQUAL(p->reverse_cursor(), 7);

	// test cursors
	print_title("test cursors");
	p = setup_picker("7654321", "       ", "", "");
	TEST_EQUAL(p->cursor(), 0);
	TEST_EQUAL(p->reverse_cursor(), 7);
	p->we_have(1);
	TEST_EQUAL(p->cursor(), 0);
	TEST_EQUAL(p->reverse_cursor(), 7);
	p->we_have(0);
	TEST_EQUAL(p->cursor(), 2);
	TEST_EQUAL(p->reverse_cursor(), 7);
	p->we_have(5);
	TEST_EQUAL(p->cursor(), 2);
	TEST_EQUAL(p->reverse_cursor(), 7);
	p->we_have(6);
	TEST_EQUAL(p->cursor(), 2);
	TEST_EQUAL(p->reverse_cursor(), 5);
	p->we_have(4);
	p->we_have(3);
	p->we_have(2);
	TEST_EQUAL(p->cursor(), 7);
	TEST_EQUAL(p->reverse_cursor(), 0);

	p = setup_picker("7654321", "       ", "", "");
	TEST_EQUAL(p->cursor() ,  0);
	TEST_EQUAL(p->reverse_cursor(), 7);
	p->set_piece_priority(1, 0);
	TEST_EQUAL(p->cursor(), 0);
	TEST_EQUAL(p->reverse_cursor(), 7);
	p->set_piece_priority(0, 0);
	TEST_EQUAL(p->cursor(), 2);
	TEST_EQUAL(p->reverse_cursor(), 7);
	p->set_piece_priority(5, 0);
	TEST_EQUAL(p->cursor(), 2);
	TEST_EQUAL(p->reverse_cursor(), 7);
	p->set_piece_priority(6, 0);
	TEST_EQUAL(p->cursor(), 2);
	TEST_EQUAL(p->reverse_cursor(), 5);
	p->set_piece_priority(4, 0);
	p->set_piece_priority(3, 0);
	p->set_piece_priority(2, 0);
	TEST_EQUAL(p->cursor(), 7);
	TEST_EQUAL(p->reverse_cursor(), 0);
	p->set_piece_priority(3, 1);
	TEST_EQUAL(p->cursor(), 3);
	TEST_EQUAL(p->reverse_cursor(), 4);

// ========================================================

	// test piece priorities
	print_title("test piece priorities");
	p = setup_picker("5555555", "       ", "7654321", "");
	TEST_CHECK(p->num_filtered() == 0);
	TEST_CHECK(p->num_have_filtered() == 0);
	p->set_piece_priority(0, 0);
	TEST_CHECK(p->num_filtered() == 1);
	TEST_CHECK(p->num_have_filtered() == 0);
	p->mark_as_finished(piece_block(0,0), 0);
	p->we_have(0);
	TEST_CHECK(p->num_filtered() == 0);
	TEST_CHECK(p->num_have_filtered() == 1);

	p->we_dont_have(0);
	p->set_piece_priority(0, 7);

	picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, 0
		, options, empty_vector);
	TEST_CHECK(int(picked.size()) == 7 * blocks_per_piece);

	for (int i = 0; i < int(picked.size()); ++i)
		TEST_CHECK(picked[i] == piece_block(i / blocks_per_piece, i % blocks_per_piece));

	// test changing priority on a piece we have
	p->we_have(0);
	p->set_piece_priority(0, 0);
	p->set_piece_priority(0, 1);
	p->set_piece_priority(0, 0);

	std::vector<int> prios;
	p->piece_priorities(prios);
	TEST_CHECK(prios.size() == 7);
	int prio_comp[] = {0, 6, 5, 4, 3, 2, 1};
	TEST_CHECK(std::equal(prios.begin(), prios.end(), prio_comp));

	std::vector<bool> filter;
	p->filtered_pieces(filter);
	TEST_CHECK(prios.size() == 7);
	bool filter_comp[] = {true, false, false, false, false, false, false};
	TEST_CHECK(std::equal(filter.begin(), filter.end(), filter_comp));

// ========================================================

	// test restore_piece
	print_title("test restore piece");
	p = setup_picker("1234567", "       ", "", "");
	p->mark_as_finished(piece_block(0,0), 0);
	p->mark_as_finished(piece_block(0,1), 0);
	p->mark_as_finished(piece_block(0,2), 0);
	p->mark_as_finished(piece_block(0,3), 0);

	picked = pick_pieces(p, "*******", 1, 0, 0, options, empty_vector);
	TEST_CHECK(int(picked.size()) >= 1);
	TEST_CHECK(picked.front().piece_index == 1);

	p->restore_piece(0);
	picked = pick_pieces(p, "*******", 1, 0, 0, options, empty_vector);
	TEST_CHECK(int(picked.size()) >= 1);
	TEST_CHECK(picked.front().piece_index == 0);

	p->mark_as_finished(piece_block(0,0), 0);
	p->mark_as_finished(piece_block(0,1), 0);
	p->mark_as_finished(piece_block(0,2), 0);
	p->mark_as_finished(piece_block(0,3), 0);
	p->set_piece_priority(0, 0);

	picked = pick_pieces(p, "*******", 1, 0, 0, options, empty_vector);
	TEST_CHECK(int(picked.size()) >= 1);
	TEST_CHECK(picked.front().piece_index == 1);

	p->restore_piece(0);
	picked = pick_pieces(p, "*******", 1, 0, 0, options, empty_vector);
	TEST_CHECK(int(picked.size()) >= 1);
	TEST_CHECK(picked.front().piece_index == 1);

	p->set_piece_priority(0, 7);
	picked = pick_pieces(p, "*******", 1, 0, 0, options, empty_vector);
	TEST_CHECK(int(picked.size()) >= 1);
	TEST_CHECK(picked.front().piece_index == 0);

// ========================================================

	// test random mode
	print_title("test random pick");
	p = setup_picker("1234567", "       ", "1111122", "");
	std::set<int> random_pieces;
	for (int i = 0; i < 100; ++i)
		random_pieces.insert(test_pick(p, 0));
	TEST_CHECK(random_pieces.size() == 7);

	random_pieces.clear();
	for (int i = 0; i < 7; ++i)
	{
		int piece = test_pick(p, 0);
		p->we_have(piece);
		random_pieces.insert(piece);
	}
	TEST_CHECK(random_pieces.size() == 7);

// ========================================================

	// make sure the piece picker will pick pieces that
	// are already requested from other peers if it has to
	print_title("test picking downloading blocks");
	p = setup_picker("1111111", "       ", "", "");
	p->mark_as_downloading(piece_block(2,2), &tmp1);
	p->mark_as_downloading(piece_block(1,2), &tmp1);

	picked.clear();
	p->pick_pieces(string2vec("*******"), picked, 7 * blocks_per_piece, 0, 0
		, piece_picker::prioritize_partials, empty_vector, 20
		, pc);
	TEST_CHECK(verify_pick(p, picked, true));
	print_pick(picked);
	// don't pick both busy pieces, if there are already other blocks picked
	TEST_EQUAL(picked.size(), 7 * blocks_per_piece - 2);

	picked.clear();
	p->pick_pieces(string2vec("*******"), picked, 7 * blocks_per_piece, 0, 0
		, piece_picker::prioritize_partials
		| piece_picker::rarest_first, empty_vector, 20
		, pc);
	TEST_CHECK(verify_pick(p, picked, true));
	print_pick(picked);
	// don't pick both busy pieces, if there are already other blocks picked
	TEST_EQUAL(picked.size(), 7 * blocks_per_piece - 2);

	picked.clear();
	p->pick_pieces(string2vec("*******"), picked, 7 * blocks_per_piece, 0, 0
		, piece_picker::rarest_first, empty_vector, 20
		, pc);
	TEST_CHECK(verify_pick(p, picked, true));
	print_pick(picked);
	// don't pick both busy pieces, if there are already other blocks picked
	TEST_EQUAL(picked.size(), 7 * blocks_per_piece - 2);

	// make sure we still pick from a partial piece even when prefering whole pieces
	picked.clear();
	p->pick_pieces(string2vec(" *     "), picked, 1, blocks_per_piece, 0
		, piece_picker::rarest_first
			| piece_picker::align_expanded_pieces, empty_vector, 20
		, pc);
	TEST_CHECK(verify_pick(p, picked, true));
	print_pick(picked);
	// always only pick one busy piece
	TEST_EQUAL(picked.size(), 1);
	TEST_CHECK(picked.size() >= 1 && picked[0].piece_index == 1);

	// don't pick locked pieces
	picked.clear();
	p->lock_piece(1);
	p->pick_pieces(string2vec(" **    "), picked, 7, 0, 0
		, piece_picker::rarest_first, empty_vector, 20
		, pc);
	TEST_CHECK(verify_pick(p, picked, true));
	print_pick(picked);
	// always only pick one busy piece
	TEST_EQUAL(picked.size(), 3);
	TEST_CHECK(picked.size() >= 1 && picked[0].piece_index == 2);

	p->restore_piece(1);
	p->mark_as_downloading(piece_block(2,0), &tmp1);
	p->mark_as_downloading(piece_block(2,1), &tmp1);
	p->mark_as_downloading(piece_block(2,3), &tmp1);
	p->mark_as_downloading(piece_block(1,0), &tmp1);
	p->mark_as_downloading(piece_block(1,1), &tmp1);
	p->mark_as_downloading(piece_block(1,2), &tmp1);
	p->mark_as_downloading(piece_block(1,3), &tmp1);

	picked.clear();
	p->pick_pieces(string2vec(" **    "), picked, 2, 0, 0
		, piece_picker::rarest_first, empty_vector, 20
		, pc);
	TEST_CHECK(verify_pick(p, picked, true));
	print_pick(picked);
	// always only pick one busy piece
	TEST_EQUAL(picked.size(), 1);

	picked.clear();
	p->pick_pieces(string2vec(" **    "), picked, 2 * blocks_per_piece, 0, 0
		, piece_picker::prioritize_partials, empty_vector, 0
		, pc);
	TEST_CHECK(verify_pick(p, picked, true));
	print_pick(picked);
	// always only pick one busy piece
	TEST_EQUAL(picked.size(), 1);

	picked.clear();
	p->pick_pieces(string2vec(" **    "), picked, 2 * blocks_per_piece, 0, 0
		, piece_picker::prioritize_partials, empty_vector, 20
		, pc);
	TEST_CHECK(verify_pick(p, picked, true));
	print_pick(picked);
	// always only pick one busy piece
	TEST_EQUAL(picked.size(), 1);

// ========================================================

	// test clear_peer
	print_title("test clear_peer");
	p = setup_picker("1123333", "       ", "", "");
	p->mark_as_downloading(piece_block(0, 0), &tmp1);
	p->mark_as_downloading(piece_block(0, 1), &tmp2);
	p->mark_as_downloading(piece_block(0, 2), &tmp3);
	p->mark_as_downloading(piece_block(1, 1), &tmp1);
	p->mark_as_downloading(piece_block(2, 1), &tmp2);
	p->mark_as_downloading(piece_block(3, 1), &tmp3);

	std::vector<torrent_peer*> dls;
	torrent_peer* expected_dls1[] = {&tmp1, &tmp2, &tmp3, 0};
	torrent_peer* expected_dls2[] = {0, &tmp1, 0, 0};
	torrent_peer* expected_dls3[] = {0, &tmp2, 0, 0};
	torrent_peer* expected_dls4[] = {0, &tmp3, 0, 0};
	torrent_peer* expected_dls5[] = {&tmp1, 0, &tmp3, 0};
	p->get_downloaders(dls, 0);
	TEST_CHECK(std::equal(dls.begin(), dls.end(), expected_dls1));
	p->get_downloaders(dls, 1);
	TEST_CHECK(std::equal(dls.begin(), dls.end(), expected_dls2));
	p->get_downloaders(dls, 2);
	TEST_CHECK(std::equal(dls.begin(), dls.end(), expected_dls3));
	p->get_downloaders(dls, 3);
	TEST_CHECK(std::equal(dls.begin(), dls.end(), expected_dls4));

	p->clear_peer(&tmp2);
	p->get_downloaders(dls, 0);
	TEST_CHECK(std::equal(dls.begin(), dls.end(), expected_dls5));

// ========================================================

	// test have_all and have_none
	print_title("test have_all and have_none");
	p = setup_picker("0123333", "*      ", "", "");
	dc = p->distributed_copies();
	std::cout << "distributed copies: " << dc.first << "." << (dc.second / 1000.f) << std::endl;
	TEST_CHECK(dc == std::make_pair(1, 5000 / 7));
	p->inc_refcount_all(&tmp8);
	dc = p->distributed_copies();
	TEST_CHECK(dc == std::make_pair(2, 5000 / 7));
	p->dec_refcount_all(&tmp8);
	dc = p->distributed_copies();
	std::cout << "distributed copies: " << dc.first << "." << (dc.second / 1000.f) << std::endl;
	TEST_CHECK(dc == std::make_pair(1, 5000 / 7));
	p->inc_refcount(0, &tmp0);
	p->dec_refcount_all(&tmp0);
	dc = p->distributed_copies();
	std::cout << "distributed copies: " << dc.first << "." << (dc.second / 1000.f) << std::endl;
	TEST_CHECK(dc == std::make_pair(0, 6000 / 7));
	TEST_CHECK(test_pick(p) == 2);

// ========================================================

	// test have_all and have_none
	print_title("test have_all and have_none with sequential download");
	p = setup_picker("0123333", "*      ", "", "");
	dc = p->distributed_copies();
	std::cout << "distributed copies: " << dc.first << "." << (dc.second / 1000.f) << std::endl;
	TEST_CHECK(dc == std::make_pair(1, 5000 / 7));
	p->inc_refcount_all(&tmp8);
	dc = p->distributed_copies();
	std::cout << "distributed copies: " << dc.first << "." << (dc.second / 1000.f) << std::endl;
	TEST_CHECK(dc == std::make_pair(2, 5000 / 7));
	TEST_CHECK(test_pick(p) == 1);

// ========================================================

	// test inc_ref and dec_ref
	print_title("test inc_ref dec_ref");
	p = setup_picker("1233333", "     * ", "", "");
	TEST_CHECK(test_pick(p) == 0);

	p->dec_refcount(0, &tmp0);
	TEST_CHECK(test_pick(p) == 1);

	p->dec_refcount(4, &tmp0);
	p->dec_refcount(4, &tmp1);
	TEST_CHECK(test_pick(p) == 4);

	// decrease refcount on something that's not in the piece list
	p->dec_refcount(5, &tmp0);
	p->inc_refcount(5, &tmp0);

	bitfield bits = string2vec("*      ");
	TEST_EQUAL(bits.get_bit(0), true);
	TEST_EQUAL(bits.get_bit(1), false);
	TEST_EQUAL(bits.get_bit(2), false);
	TEST_EQUAL(bits.get_bit(3), false);
	TEST_EQUAL(bits.get_bit(4), false);
	TEST_EQUAL(bits.get_bit(5), false);
	TEST_EQUAL(bits.get_bit(6), false);
	p->inc_refcount(bits, &tmp0);
	bits = string2vec("    *  ");

	TEST_EQUAL(bits.get_bit(0), false);
	TEST_EQUAL(bits.get_bit(1), false);
	TEST_EQUAL(bits.get_bit(2), false);
	TEST_EQUAL(bits.get_bit(3), false);
	TEST_EQUAL(bits.get_bit(4), true);
	TEST_EQUAL(bits.get_bit(5), false);
	TEST_EQUAL(bits.get_bit(6), false);
	p->dec_refcount(bits, &tmp2);
	TEST_EQUAL(test_pick(p), 0);

// ========================================================

	// test unverified_blocks, marking blocks and get_downloader
	print_title("test unverified blocks");
	p = setup_picker("1111111", "       ", "", "0300700");
	TEST_CHECK(p->unverified_blocks() == 2 + 3);
	TEST_CHECK(p->get_downloader(piece_block(4, 0)) == tmp_peer);
	TEST_CHECK(p->get_downloader(piece_block(4, 1)) == tmp_peer);
	TEST_CHECK(p->get_downloader(piece_block(4, 2)) == tmp_peer);
	TEST_CHECK(p->get_downloader(piece_block(4, 3)) == 0);
	p->mark_as_downloading(piece_block(4, 3), &peer_struct);
	TEST_CHECK(p->get_downloader(piece_block(4, 3)) == &peer_struct);
	p->piece_info(4, st);
	TEST_CHECK(st.requested == 1);
	TEST_CHECK(st.writing == 0);
	TEST_CHECK(st.finished == 3);
	TEST_CHECK(p->unverified_blocks() == 2 + 3);
	p->mark_as_writing(piece_block(4, 3), &peer_struct);
	TEST_CHECK(p->get_downloader(piece_block(4, 3)) == &peer_struct);
	p->piece_info(4, st);
	TEST_CHECK(st.requested == 0);
	TEST_CHECK(st.writing == 1);
	TEST_CHECK(st.finished == 3);
	TEST_CHECK(p->unverified_blocks() == 2 + 3);
	p->mark_as_finished(piece_block(4, 3), &peer_struct);
	TEST_CHECK(p->get_downloader(piece_block(4, 3)) == &peer_struct);
	p->piece_info(4, st);
	TEST_CHECK(st.requested == 0);
	TEST_CHECK(st.writing == 0);
	TEST_CHECK(st.finished == 4);
	TEST_CHECK(p->unverified_blocks() == 2 + 4);
	p->we_have(4);
	p->piece_info(4, st);
	TEST_CHECK(st.requested == 0);
	TEST_CHECK(st.writing == 0);
	TEST_CHECK(st.finished == 4);
	TEST_CHECK(p->get_downloader(piece_block(4, 3)) == 0);
	TEST_CHECK(p->unverified_blocks() == 2);

// ========================================================

	// test prefer_contiguous_blocks
	print_title("test prefer contiguous blocks");
	p = setup_picker("1111111", "       ", "", "");
	picked = pick_pieces(p, "*******", 1, 3 * blocks_per_piece
		, 0, options, empty_vector);
	TEST_CHECK(int(picked.size()) >= 3 * blocks_per_piece);
	piece_block b = picked.front();
	for (int i = 1; i < int(picked.size()); ++i)
	{
		TEST_CHECK(picked[i].piece_index * blocks_per_piece + picked[i].block_index
			== b.piece_index * blocks_per_piece + b.block_index + 1);
		b = picked[i];
	}

	picked = pick_pieces(p, "*******", 1, 3 * blocks_per_piece
		, 0, options, empty_vector);
	TEST_CHECK(int(picked.size()) >= 3 * blocks_per_piece);
	b = picked.front();
	for (int i = 1; i < int(picked.size()); ++i)
	{
		TEST_CHECK(picked[i].piece_index * blocks_per_piece + picked[i].block_index
			== b.piece_index * blocks_per_piece + b.block_index + 1);
		b = picked[i];
	}

	// make sure pieces that don't match the 'whole pieces' requirement
	// are picked if there's no other choice
	p = setup_picker("1111111", "       ", "", "");
	p->mark_as_downloading(piece_block(2,2), &tmp1);
	picked = pick_pieces(p, "*******", 7 * blocks_per_piece - 1, blocks_per_piece
		, 0, options, empty_vector);
	TEST_CHECK(picked.size() == 7 * blocks_per_piece - 1);
	TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(2,2)) == picked.end());

	// test aligned whole pieces
	print_title("test prefer aligned whole pieces");
	p = setup_picker("2222221222222222", "                ", "", "");
	picked = pick_pieces(p, "****************", 1, 4 * blocks_per_piece, 0
		, options | piece_picker::align_expanded_pieces, empty_vector);

	// the piece picker should pick piece 5, and then align it to even 4 pieces
	// i.e. it should have picked pieces: 4,5,6,7
	print_pick(picked);
	TEST_EQUAL(picked.size() , 4 * blocks_per_piece);

	std::set<int> picked_pieces;
	for (std::vector<piece_block>::iterator i = picked.begin()
		, end(picked.end()); i != end; ++i)
		picked_pieces.insert(picked_pieces.begin(), i->piece_index);

	TEST_CHECK(picked_pieces.size() == 4);
	int expected_pieces[] = {4,5,6,7};
	TEST_CHECK(std::equal(picked_pieces.begin(), picked_pieces.end(), expected_pieces))

//#error test picking with partial pieces and other peers present so that both backup_pieces and backup_pieces2 are used

// ========================================================

	// test parole mode
	print_title("test parole mode");
	p = setup_picker("3333133", "       ", "", "");
	p->mark_as_finished(piece_block(0, 0), 0);
	picked = pick_pieces(p, "*******", 1, blocks_per_piece, 0

		, options | piece_picker::on_parole | piece_picker::prioritize_partials, empty_vector);
	TEST_EQUAL(int(picked.size()), blocks_per_piece - 1);
	for (int i = 1; i < int(picked.size()); ++i)
		TEST_CHECK(picked[i] == piece_block(0, i + 1));

	//	make sure that the partial piece is not picked by a
	// peer that is has not downloaded/requested the other blocks
	picked = pick_pieces(p, "*******", 1, blocks_per_piece
		, &peer_struct
		, options | piece_picker::on_parole | piece_picker::prioritize_partials, empty_vector);
	TEST_EQUAL(int(picked.size()), blocks_per_piece);
	for (int i = 1; i < int(picked.size()); ++i)
		TEST_CHECK(picked[i] == piece_block(4, i));

// ========================================================

	// test suggested pieces
	print_title("test suggested pieces");
	p = setup_picker("1111222233334444", "                ", "", "");
	int v[] = {1, 5};
	const std::vector<int> suggested_pieces(v, v + 2);

	picked = pick_pieces(p, "****************", 1, blocks_per_piece
		, 0, options, suggested_pieces);
	TEST_CHECK(int(picked.size()) >= blocks_per_piece);
	for (int i = 1; i < int(picked.size()); ++i)
		TEST_CHECK(picked[i] == piece_block(1, i));
	p->set_piece_priority(0, 0);
	p->set_piece_priority(1, 0);
	p->set_piece_priority(2, 0);
	p->set_piece_priority(3, 0);

	picked = pick_pieces(p, "****************", 1, blocks_per_piece
		, 0, options, suggested_pieces);
	TEST_CHECK(int(picked.size()) >= blocks_per_piece);
	for (int i = 1; i < int(picked.size()); ++i)
		TEST_CHECK(picked[i] == piece_block(5, i));

	p = setup_picker("1111222233334444", "****            ", "", "");
	picked = pick_pieces(p, "****************", 1, blocks_per_piece
		, 0, options, suggested_pieces);
	TEST_CHECK(int(picked.size()) >= blocks_per_piece);
	for (int i = 1; i < int(picked.size()); ++i)
		TEST_CHECK(picked[i] == piece_block(5, i));

// ========================================================

	// test bitfield optimization
	print_title("test bitfield optimization");
	// we have less than half of the pieces
	p = setup_picker("2122222211221222", "                ", "", "");
	// make sure it's not dirty
	pick_pieces(p, "****************", 1, blocks_per_piece, 0);
	print_availability(p);
	p->dec_refcount(string2vec("**  **  **  *   "), &tmp0);
	print_availability(p);
	TEST_CHECK(verify_availability(p, "1022112200220222"));
	// make sure it's not dirty
	pick_pieces(p, "****************", 1, blocks_per_piece, 0);
	p->inc_refcount(string2vec(" **  **  *   *  "), &tmp8);
	print_availability(p);
	TEST_CHECK(verify_availability(p, "1132123201220322"));

// ========================================================

	// test seed optimizaton
	print_title("test seed optimization");
	p = setup_picker("0000000000000000", "                ", "", "");

	// make sure it's not dirty
	pick_pieces(p, "****************", 1, blocks_per_piece, 0);

	p->inc_refcount_all(&tmp0);
	print_availability(p);
	TEST_CHECK(verify_availability(p, "1111111111111111"));

	pick_pieces(p, "****************", 1, blocks_per_piece, 0);
	p->dec_refcount(string2vec("  ****  **      "), &tmp0);
	print_availability(p);
	TEST_CHECK(verify_availability(p, "1100001100111111"));

	pick_pieces(p, "****************", 1, blocks_per_piece, 0);
	p->inc_refcount(string2vec("  ****  **      "), &tmp0);
	TEST_CHECK(verify_availability(p, "1111111111111111"));

	pick_pieces(p, "****************", 1, blocks_per_piece, 0);
	p->dec_refcount_all(&tmp0);
	TEST_CHECK(verify_availability(p, "0000000000000000"));

	p->inc_refcount_all(&tmp1);
	print_availability(p);
	TEST_CHECK(verify_availability(p, "1111111111111111"));

	pick_pieces(p, "****************", 1, blocks_per_piece, 0);
	p->dec_refcount(3, &tmp1);
	print_availability(p);
	TEST_CHECK(verify_availability(p, "1110111111111111"));

	p->inc_refcount(string2vec("****************"), &tmp2);
	print_availability(p);
	TEST_CHECK(verify_availability(p, "2221222222222222"));

	p->inc_refcount(string2vec("* * * * * * * * "), &tmp3);
	print_availability(p);
	TEST_CHECK(verify_availability(p, "3231323232323232"));

	p->dec_refcount(string2vec("****************"), &tmp2);
	print_availability(p);
	TEST_CHECK(verify_availability(p, "2120212121212121"));

	p->dec_refcount(string2vec("* * * * * * * * "), &tmp3);
	print_availability(p);
	TEST_CHECK(verify_availability(p, "1110111111111111"));

// ========================================================

	// test reversed peers
	print_title("test reversed peers");
	p = setup_picker("3333333", "  *****", "", "");

	// a reversed peer picked a block from piece 0
	// This should make the piece reversed
	p->mark_as_downloading(piece_block(0,0), &tmp1
		, piece_picker::reverse);

	TEST_EQUAL(test_pick(p, piece_picker::rarest_first), 1);

	// make sure another reversed peer pick the same piece
	TEST_EQUAL(test_pick(p, piece_picker::rarest_first | piece_picker::reverse), 0);

// ========================================================

	// test reversed pieces upgrading to normal pieces
	print_title("test reversed piece upgrade");

	p = setup_picker("3333333", "  *****", "", "");

	// make piece 0 partial and reversed
	p->mark_as_downloading(piece_block(0,1), &tmp1
		, piece_picker::reverse);
	TEST_EQUAL(test_pick(p), 1);

	// now have a regular peer pick the reversed block. It should now
	// have turned into a regular one and be prioritized
	p->mark_as_downloading(piece_block(0,2), &tmp1);
	TEST_EQUAL(test_pick(p), 0);

// ========================================================

	// test pieces downgrading to reversed pieces
	print_title("test reversed piece downgrade");
// now make sure a piece can be demoted to reversed if there are no
// other outstanding requests

	p = setup_picker("3333333", "       ", "", "");

	// make piece 0 partial and not reversed
	p->mark_as_finished(piece_block(0,1), &tmp1);

	// a reversed peer picked a block from piece 0
	// This should make the piece reversed
	p->mark_as_downloading(piece_block(0,0), &tmp1
		, piece_picker::reverse);

	TEST_EQUAL(test_pick(p, piece_picker::rarest_first | piece_picker::reverse), 0);

// ========================================================

	print_title("test piece_stats");

	p = setup_picker("3456789", "*      ", "", "0300000");

	piece_picker::piece_stats_t stat = p->piece_stats(0);
	TEST_EQUAL(stat.peer_count, 3);
	TEST_EQUAL(stat.have, 1);
	TEST_EQUAL(stat.downloading, 0);

	stat = p->piece_stats(1);
	TEST_EQUAL(stat.peer_count, 4);
	TEST_EQUAL(stat.have, 0);
	TEST_EQUAL(stat.downloading, 1);

// ========================================================

	print_title("test piece passed");

	p = setup_picker("1111111", "*      ", "", "0300000");

	TEST_EQUAL(p->has_piece_passed(0), true);
	TEST_EQUAL(p->has_piece_passed(1), false);
	TEST_EQUAL(p->num_passed(), 1);
	TEST_EQUAL(p->num_have(), 1);

	p->piece_passed(1);
	TEST_EQUAL(p->num_passed(), 2);
	TEST_EQUAL(p->num_have(), 1);

	p->we_have(1);
	TEST_EQUAL(p->num_have(), 2);

	p->mark_as_finished(piece_block(2,0), &tmp1);
	p->piece_passed(2);
	TEST_EQUAL(p->num_passed(), 3);
	// just because the hash check passed doesn't mean
	// we "have" the piece. We need to write it to disk first
	TEST_EQUAL(p->num_have(), 2);

	// piece 2 already passed the hash check, as soon as we've
	// written all the blocks to disk, we should have that piece too
	p->mark_as_finished(piece_block(2,1), &tmp1);
	p->mark_as_finished(piece_block(2,2), &tmp1);
	p->mark_as_finished(piece_block(2,3), &tmp1);
	TEST_EQUAL(p->num_have(), 3);
	TEST_EQUAL(p->have_piece(2), true);

// ========================================================

	print_title("test piece passed (causing we_have)");

	p = setup_picker("1111111", "*      ", "", "0700000");

	TEST_EQUAL(p->has_piece_passed(0), true);
	TEST_EQUAL(p->has_piece_passed(1), false);
	TEST_EQUAL(p->num_passed(), 1);
	TEST_EQUAL(p->num_have(), 1);

	p->mark_as_finished(piece_block(1,3), &tmp1);
	TEST_EQUAL(p->num_passed(), 1);
	TEST_EQUAL(p->num_have(), 1);

	p->piece_passed(1);
	TEST_EQUAL(p->num_passed(), 2);
	TEST_EQUAL(p->num_have(), 2);

// ========================================================

	print_title("test break_one_seed");

	p = setup_picker("0000000", "*      ", "", "0700000");
	p->inc_refcount_all(&tmp1);
	p->inc_refcount_all(&tmp2);
	p->inc_refcount_all(&tmp3);

	TEST_EQUAL(p->piece_stats(0).peer_count, 3);

	p->dec_refcount(0, &tmp1);

	TEST_EQUAL(p->piece_stats(0).peer_count, 2);
	TEST_EQUAL(p->piece_stats(1).peer_count, 3);
	TEST_EQUAL(p->piece_stats(2).peer_count, 3);
	TEST_EQUAL(p->piece_stats(3).peer_count, 3);

// ========================================================

	print_title("test we dont have");

	p = setup_picker("1111111", "* *    ", "1101111", "");
	TEST_EQUAL(p->has_piece_passed(0), true);
	TEST_EQUAL(p->has_piece_passed(1), false);
	TEST_EQUAL(p->has_piece_passed(2), true);
	TEST_EQUAL(p->num_passed(), 2);
	TEST_EQUAL(p->num_have(), 2);
	TEST_EQUAL(p->num_have_filtered(), 1);
	TEST_EQUAL(p->num_filtered(), 0);

	p->we_dont_have(0);

	TEST_EQUAL(p->has_piece_passed(0), false);
	TEST_EQUAL(p->has_piece_passed(1), false);
	TEST_EQUAL(p->has_piece_passed(2), true);
	TEST_EQUAL(p->num_passed(), 1);
	TEST_EQUAL(p->num_have(), 1);
	TEST_EQUAL(p->num_have_filtered(), 1);

	p = setup_picker("1111111", "* *    ", "1101111", "");
	TEST_EQUAL(p->has_piece_passed(0), true);
	TEST_EQUAL(p->has_piece_passed(1), false);
	TEST_EQUAL(p->has_piece_passed(2), true);
	TEST_EQUAL(p->num_passed(), 2);
	TEST_EQUAL(p->num_have(), 2);
	TEST_EQUAL(p->num_have_filtered(), 1);
	TEST_EQUAL(p->num_filtered(), 0);

	p->we_dont_have(2);

	TEST_EQUAL(p->has_piece_passed(0), true);
	TEST_EQUAL(p->has_piece_passed(1), false);
	TEST_EQUAL(p->has_piece_passed(2), false);
	TEST_EQUAL(p->num_passed(), 1);
	TEST_EQUAL(p->num_have(), 1);
	TEST_EQUAL(p->num_have_filtered(), 0);

// ========================================================

	print_title("test we dont have (don't have but passed hash check)");

	p = setup_picker("1111111", "* *    ", "1101111", "0200000");

	TEST_EQUAL(p->has_piece_passed(0), true);
	TEST_EQUAL(p->has_piece_passed(1), false);
	TEST_EQUAL(p->have_piece(0), true)
	TEST_EQUAL(p->have_piece(1), false)

	p->piece_passed(1);

	TEST_EQUAL(p->has_piece_passed(0), true);
	TEST_EQUAL(p->has_piece_passed(1), true);
	TEST_EQUAL(p->have_piece(1), false)

	p->we_dont_have(1);

	TEST_EQUAL(p->has_piece_passed(0), true);
	TEST_EQUAL(p->has_piece_passed(1), false);
	TEST_EQUAL(p->have_piece(1), false)

// ========================================================

	print_title("test write_failed");

	p = setup_picker("1111111", "* *    ", "1101111", "0200000");

	TEST_EQUAL(p->has_piece_passed(0), true);
	TEST_EQUAL(p->has_piece_passed(1), false);
	TEST_EQUAL(p->have_piece(1), false);

	p->piece_passed(1);

	TEST_EQUAL(p->has_piece_passed(0), true);
	TEST_EQUAL(p->has_piece_passed(1), true);
	TEST_EQUAL(p->have_piece(1), false);

	p->mark_as_writing(piece_block(1, 0), &tmp1);
	p->write_failed(piece_block(1, 0));

	TEST_EQUAL(p->has_piece_passed(0), true);
	TEST_EQUAL(p->has_piece_passed(1), false);
	TEST_EQUAL(p->have_piece(1), false);

	// make sure write_failed() and lock_piece() actually
	// locks the piece, and that it won't be picked.
	// also make sure restore_piece() unlocks it and makes
	// it available for picking again.

	picked = pick_pieces(p, " *     ", 1, blocks_per_piece, 0);
	TEST_EQUAL(picked.size(), 0);

	p->restore_piece(1);

	picked = pick_pieces(p, " *     ", 1, blocks_per_piece, 0);
	TEST_EQUAL(picked.size(), blocks_per_piece);

	// locking pieces only works on partial pieces
	p->mark_as_writing(piece_block(1, 0), &tmp1);
	p->lock_piece(1);

	picked = pick_pieces(p, " *     ", 1, blocks_per_piece, 0);
	TEST_EQUAL(picked.size(), 0);

// ========================================================

	print_title("test write_failed (clear piece)");

	p = setup_picker("1111111", "* *    ", "1101111", "");

	stat = p->piece_stats(1);
	TEST_EQUAL(stat.downloading, 0);

	p->mark_as_writing(piece_block(1, 0), &tmp1);

	stat = p->piece_stats(1);
	TEST_EQUAL(stat.downloading, 1);

	p->write_failed(piece_block(1, 0));

	stat = p->piece_stats(1);
	TEST_EQUAL(stat.downloading, 0);

// ========================================================

	print_title("test mark_as_canceled");

	p = setup_picker("1111111", "* *    ", "1101111", "");

	stat = p->piece_stats(1);
	TEST_EQUAL(stat.downloading, 0);

	p->mark_as_writing(piece_block(1, 0), &tmp1);

	stat = p->piece_stats(1);
	TEST_EQUAL(stat.downloading, 1);

	p->mark_as_canceled(piece_block(1, 0), &tmp1);
	stat = p->piece_stats(1);
	TEST_EQUAL(stat.downloading, 0);

// ========================================================

	print_title("test get_download_queue");

	p = setup_picker("1111111", "       ", "1101111", "0327000");

	std::vector<piece_picker::downloading_piece> downloads
		= p->get_download_queue();

	// the download queue should have piece 1, 2 and 3 in it
	TEST_EQUAL(downloads.size(), 3);

	TEST_EQUAL(std::count_if(downloads.begin(), downloads.end()
		, [](piece_picker::downloading_piece const& p) { return p.index == 1; }), 1);
	TEST_EQUAL(std::count_if(downloads.begin(), downloads.end()
		, [](piece_picker::downloading_piece const& p) { return p.index == 2; }), 1);
	TEST_EQUAL(std::count_if(downloads.begin(), downloads.end()
		, [](piece_picker::downloading_piece const& p) { return p.index == 3; }), 1);

// ========================================================

	print_title("test get_download_queue_size");

	p = setup_picker("1111111", "       ", "1111111", "0327ff0");

	TEST_EQUAL(p->get_download_queue_size(), 5);

	p->set_piece_priority(1, 0);

	int partial;
	int full;
	int finished;
	int zero_prio;
	p->get_download_queue_sizes(&partial, &full, &finished, &zero_prio);

	TEST_EQUAL(partial, 2);
	TEST_EQUAL(full, 0);
	TEST_EQUAL(finished, 2);
	TEST_EQUAL(zero_prio, 1);

// ========================================================

	print_title("test time_critical_mode");

	p = setup_picker("1111111", "       ", "1654741", "0352000");

	// rarest-first
	picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, tmp_peer
		, piece_picker::rarest_first | piece_picker::time_critical_mode, empty_vector);
	TEST_EQUAL(picked.size(), blocks_per_piece);
	for (int i = 0; i < int(picked.size()); ++i)
		TEST_EQUAL(picked[0].piece_index, 4);

	// reverse rarest-first
	picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, tmp_peer
		, piece_picker::reverse | piece_picker::rarest_first
		| piece_picker::time_critical_mode, empty_vector);
	TEST_EQUAL(picked.size(), blocks_per_piece);
	for (int i = 0; i < int(picked.size()); ++i)
		TEST_EQUAL(picked[0].piece_index, 4);

	// sequential
	picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, tmp_peer
		, piece_picker::sequential | piece_picker::time_critical_mode, empty_vector);
	TEST_EQUAL(picked.size(), blocks_per_piece);
	for (int i = 0; i < int(picked.size()); ++i)
		TEST_EQUAL(picked[0].piece_index, 4);

	// reverse sequential
	picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, tmp_peer
		, piece_picker::reverse | piece_picker::sequential
		| piece_picker::time_critical_mode, empty_vector);
	TEST_EQUAL(picked.size(), blocks_per_piece);
	for (int i = 0; i < int(picked.size()); ++i)
		TEST_EQUAL(picked[0].piece_index, 4);

	// just critical
	picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, tmp_peer
		, piece_picker::time_critical_mode, empty_vector);
	TEST_EQUAL(picked.size(), blocks_per_piece);
	for (int i = 0; i < int(picked.size()); ++i)
		TEST_EQUAL(picked[0].piece_index, 4);

	// prioritize_partials
	picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, tmp_peer
		, piece_picker::prioritize_partials | piece_picker::time_critical_mode, empty_vector);
	TEST_EQUAL(picked.size(), blocks_per_piece);
	for (int i = 0; i < int(picked.size()); ++i)
		TEST_EQUAL(picked[0].piece_index, 4);

	// even when a non-critical piece is suggested should we ignore it
	picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, tmp_peer
		, piece_picker::rarest_first | piece_picker::time_critical_mode
		, suggested_pieces);
	TEST_EQUAL(picked.size(), blocks_per_piece);
	for (int i = 0; i < int(picked.size()); ++i)
		TEST_EQUAL(picked[0].piece_index, 4);
}

ext: cpp

max_stars_repo_name: ssiloti/libtorrent

max_issues_repo_name: ssiloti/libtorrent

max_forks_repo_name: ssiloti/libtorrent


text:
//============================================================================
//
// This file is part of the Thea toolkit.
//
// This software is distributed under the BSD license, as detailed in the
// accompanying LICENSE.txt file. Portions are derived from other works:
// their respective licenses and copyright information are reproduced in
// LICENSE.txt and/or in the relevant source files.
//
// Author: Siddhartha Chaudhuri
// First version: 2013
//
//============================================================================

#include "FileSystem.hpp"
#include "StringAlg.hpp"
#include <boost/cstdint.hpp>
#include <boost/filesystem.hpp>
#include <boost/version.hpp>
#include <algorithm>
#include <cstdio>

namespace Thea {

bool
FileSystem::exists(std::string const & path)
{
  return boost::filesystem::exists(path);
}

bool
FileSystem::fileExists(std::string const & path)
{
  return boost::filesystem::is_regular_file(path);
}

bool
FileSystem::directoryExists(std::string const & path)
{
  return boost::filesystem::is_directory(path);
}

int64
FileSystem::fileSize(std::string const & path)
{
  boost::uintmax_t size = boost::filesystem::file_size(path);
  if (size == static_cast<boost::uintmax_t>(-1))
    return -1;
  else
    return static_cast<int64>(size);
}

std::string
FileSystem::resolve(std::string const & path)
{
  return boost::filesystem::system_complete(path).string();
}

bool
FileSystem::createDirectory(std::string const & path)
{
  if (directoryExists(path))
    return true;

  return boost::filesystem::create_directories(path);
}

bool
FileSystem::readWholeFile(std::string const & path, std::string & ret)
{
  if (!fileExists(path))
  {
    THEA_ERROR << "FileSystem: File '" << path << "' not found";
    return false;
  }

  int64 length = fileSize(path);
  if (length <= 0)
  {
    ret.clear();
    return true;
  }

  char * buffer = (char *)std::malloc((size_t)length);
  if (!buffer)
  {
    THEA_ERROR << "FileSystem: Could not allocate buffer to hold " << length << " bytes from file '" << path << '\'';
    return false;
  }

  FILE * f = std::fopen(path.c_str(), "rb");
  if (!f)
  {
    THEA_ERROR << "FileSystem: Couldn't open file '" << path << "' for reading";
    return false;
  }

  size_t num_read = std::fread(buffer, 1, length, f);
  if ((int64)num_read != length)
  {
    THEA_ERROR << "FileSystem: Error reading from file '" << path << '\'';
    return false;
  }

  std::fclose(f);

  ret.assign(buffer, (size_t)length);
  std::free(buffer);

  return true;
}

namespace FileSystemInternal {

bool
objectSatisfiesConstraints(boost::filesystem::directory_entry const & object, int types,
                           Array<std::string> const & patterns, bool ignore_case)
{
  if (types > 0 && types != FileSystem::ObjectType::ALL)
  {
    boost::filesystem::file_status status = object.symlink_status();
    if (!boost::filesystem::is_symlink(status))
      status = object.status();

    bool ok = false;

    if (!ok && (types & FileSystem::ObjectType::FILE) && boost::filesystem::is_regular_file(status))
      ok = true;

    if (!ok && (types & FileSystem::ObjectType::DIRECTORY) && boost::filesystem::is_directory(status))
      ok = true;

    if (!ok && (types & FileSystem::ObjectType::SYMLINK) && boost::filesystem::is_symlink(status))
      ok = true;

    if (!ok)
      return false;
  }

  if (!patterns.empty())
  {
#if BOOST_VERSION / 100000 > 1 || (BOOST_VERSION / 100000 == 1 && BOOST_VERSION / 100 % 1000 > 45)
    std::string name = object.path().filename().string();
#else
    std::string name = object.path().filename();
#endif

    if (ignore_case)
      name = toLower(name);

    bool ok = false;
    for (size_t i = 0; !ok && i < patterns.size(); ++i)
      if (patternMatch(patterns[i], name))
        ok = true;

    if (!ok)
      return false;
  }

  return true;
}

} // namespace FileSystemInternal

intx
FileSystem::getDirectoryContents(std::string const & dir, Array<std::string> & objects, int types, std::string const & patterns,
                                 int flags)
{
  if (!directoryExists(dir))
    return -1;

  bool ignore_case  =  (flags & Flags::CASE_INSENSITIVE);
  bool recursive    =  (flags & Flags::RECURSIVE);
  bool sorted       =  (flags & Flags::SORTED);

  Array<std::string> patlist;
  if (!patterns.empty())
  {
    stringSplit(patterns, ' ', patlist, true);

    if (ignore_case)
    {
      for (size_t i = 0; i < patlist.size(); ++i)
        patlist[i] = toLower(patlist[i]);
    }
  }

  objects.clear();

  if (recursive)
  {
    boost::filesystem::recursive_directory_iterator objects_end;
    for (boost::filesystem::recursive_directory_iterator iter(dir); iter != objects_end; ++iter)
      if (FileSystemInternal::objectSatisfiesConstraints(*iter, types, patlist, ignore_case))
        objects.push_back(iter->path().string());
  }
  else
  {
    boost::filesystem::directory_iterator objects_end;
    for (boost::filesystem::directory_iterator iter(dir); iter != objects_end; ++iter)
      if (FileSystemInternal::objectSatisfiesConstraints(*iter, types, patlist, ignore_case))
        objects.push_back(iter->path().string());
  }

  if (sorted)
    std::sort(objects.begin(), objects.end());

  return (intx)objects.size();
}

bool
FileSystem::remove(std::string const & path, bool recursive)
{
  try
  {
    if (recursive)
      boost::filesystem::remove_all(path);
    else
      boost::filesystem::remove(path);
  }
  catch (...)
  {
    return false;
  }

  return true;
}

bool
FileSystem::copyFile(std::string const & from, std::string const & to)
{
  try
  {
    boost::filesystem::copy_file(from, to);
  }
  catch (...)
  {
    return false;
  }

  return true;
}

} // namespace Thea

max_stars_repo_name: christinazavou/Thea

max_issues_repo_name: christinazavou/Thea

max_forks_repo_name: christinazavou/Thea


text:
#pragma once

#include <memory>
#include <vector>
#include <boost/variant.hpp>

namespace kaleidoscope {
    namespace syntax {

        class ast_node {
        public:
            ast_node(): id_(i++) {}
            int id() const { return id_; }
        private:
            static int i;
            int id_;
        };

        // forward declarations
        class number_expr;
        class variable_expr;
        class binary_expr;
        class call_expr;

#       define DEFINE_PTR_ALIAS(node) using node##_ptr = std::shared_ptr<node>;

        DEFINE_PTR_ALIAS(number_expr);
        DEFINE_PTR_ALIAS(variable_expr);
        DEFINE_PTR_ALIAS(binary_expr);
        DEFINE_PTR_ALIAS(call_expr);

        using any_expr = boost::variant <
                            number_expr_ptr,
                            variable_expr_ptr,
                            binary_expr_ptr,
                            call_expr_ptr
                        >
                        ;

        class expr : public ast_node {};

        class number_expr : public expr {
        public:
            number_expr(double v)
                : value_(v) {}

            bool operator ==(number_expr const& rhs)
            {
                auto diff = value_ - rhs.value_;
                return diff < 0.0001 && -diff < 0.0001;
            }

            double value() const noexcept { return value_; }

        private:
            double value_;
        };

        class variable_expr : public expr {
        public:
            variable_expr(std::string const& name)
                : name_(name) {}

            bool operator ==(variable_expr const& rhs)
            {
                return name_ == rhs.name_;
            }

            std::string const& name() const noexcept { return name_; }

        private:
            std::string name_;
        };

        class binary_expr : public expr {
        public:
            binary_expr(char const op, any_expr const& lhs, any_expr const& rhs)
                : op_(op), lhs_(lhs), rhs_(rhs) {}

            bool operator==(binary_expr const& rhs)
            {
                return op_ == rhs.op_ && lhs_ == rhs.lhs_ && rhs_ == rhs.rhs_;
            }

            char op() const noexcept { return op_; }
            any_expr const& lhs() const noexcept { return lhs_; }
            any_expr const& rhs() const noexcept { return rhs_; }

        private:
            char op_;
            any_expr lhs_, rhs_;
        };

        class call_expr : public expr {
        public:
            call_expr(std::string const& callee,
                      std::vector<any_expr> const& args)
                : callee_(callee), args_(args) {}

            bool operator==(call_expr const& rhs)
            {
                return callee_ == rhs.callee_ && args_ == rhs.args_;
            }

        private:
            std::string callee_;
            std::vector<any_expr> args_;
        };

        class prototype : public ast_node {
        public:
            prototype(std::string const& name, std::vector<std::string> const& args)
                : name_(name), args_(args) {}

            bool operator==(prototype const& rhs)
            {
                return name_ == rhs.name_ && args_ == rhs.args_;
            }

        private:
            std::string name_;
            std::vector<std::string> args_;
        };

        class func : public ast_node {
        public:
            func(prototype const& proto, any_expr const& body)
                : proto_(proto), body_(body) {}

            bool operator==(func const& rhs)
            {
                return proto_ == rhs.proto_ && body_ == rhs.body_;
            }

            prototype const& proto() const noexcept { return proto_; }
            any_expr const& body() const noexcept { return body_; }

        private:
            prototype proto_;
            any_expr body_;
        };

    } // namespace syntax
} // namespace kaleidoscope

ext: hpp

max_stars_repo_name: agatan/kaleidoscope-cpp

max_issues_repo_name: agatan/kaleidoscope-cpp

max_forks_repo_name: agatan/kaleidoscope-cpp


text:
/*
 * Copyright (c) 2015 lastz.org
 *
 * File:      corpus.cc
 * Project:   datagraph
 * Author:    Jason Su <uukuguy@gmail.com>
 *
 * Modified:
 * Created:   2015-01-10 15:31:13
 *
 * Licence: MIT
 *
 */

#include "corpus.h"
#include "docset.h"
#include "document.h"
#include "logger.h"
#include "filesystem.h"
#include <boost/filesystem.hpp>
#include <stdlib.h>

corpus_t *corpus_new(const char *name, const char *rootdir)
{
    corpus_t *corpus = (corpus_t*)malloc(sizeof(corpus_t));
    memset(corpus, 0, sizeof(corpus_t));

    Corpus *pCorpus = new Corpus(name, rootdir);
    corpus->pCorpus = pCorpus;

    return corpus;
}

void corpus_free(corpus_t *corpus)
{
    Corpus *pCorpus = (Corpus*)(corpus->pCorpus);
    delete pCorpus;
    free(corpus);
}

corpus_t *corpus_attach(void *pCorpus)
{
    corpus_t *corpus = (corpus_t*)malloc(sizeof(corpus_t));
    memset(corpus, 0, sizeof(corpus_t));

    corpus->pCorpus = pCorpus;
    return corpus;
}

void corpus_detach(corpus_t *corpus)
{
    free(corpus);
}

int corpus_load_from_files(corpus_t *corpus)
{
    Corpus *pCorpus = (Corpus*)(corpus->pCorpus);
    return pCorpus->load_from_files();
}

int corpus_segment_files(corpus_t *corpus)
{
    Corpus *pCorpus = (Corpus*)(corpus->pCorpus);
    return pCorpus->segment_files();
}

int corpus_load_segment_files(corpus_t *corpus)
{
    Corpus *pCorpus = (Corpus*)(corpus->pCorpus);
    return pCorpus->load_segment_files();
}

int corpus_save_segment_files(corpus_t *corpus)
{
    Corpus *pCorpus = (Corpus*)(corpus->pCorpus);
    return pCorpus->save_segment_files();
}

// ================ class Corpus ================

Corpus::Corpus(const std::string& name, const std::string& rootdir)
    : m_name(name), m_rootdir(rootdir), m_status(CORPUS_STATUS_NONE)
{
    std::string corpus_dir = rootdir + "/" + name;
    std::string puretext_dir = corpus_dir + "/" + "puretext";
    std::string segment_dir = corpus_dir + "/" + "segment";

    mkdir_if_not_exist(rootdir.c_str());
    mkdir_if_not_exist(corpus_dir.c_str());
    mkdir_if_not_exist(puretext_dir.c_str());
    mkdir_if_not_exist(segment_dir.c_str());

    m_pRootDocset = new Docset(this, 0, "Default");
}

Corpus::~Corpus()
{
    clear();
    delete m_pRootDocset;
}

void Corpus::clear()
{
    m_pRootDocset->clear();
}

int Corpus::add_files(const std::string& files_rootdir, const std::string& file_extension)
{
    int ret = 0;
    //boost::filesystem::path bp(files_rootdir);
    //boost::filesystem::directory_iterator end_iter;
    //for ( boost::filesystem::directory_iterator file_iter(bp) ; file_iter != end_iter ; ++file_iter) {
        //boost::filesystem::path filepath = boost::filesystem::system_complete(*file_iter);
        //if ( filepath.extension() == file_extension ) {
            //std::string strFilePath = filepath.generic_string();
        //}
    //}

    return ret;
}

int Corpus::load_from_files()
{
    int ret = 0;

    std::string puretext_rootdir = m_rootdir + "/" + m_name + "/puretext";
    ret = m_pRootDocset->load_from_files(puretext_rootdir);

    if ( ret == 0 ){
        m_status = CORPUS_STATUS_DOCUMENTS_READY;
    }

    return ret;
}

int Corpus::segment_files()
{
    int ret = m_pRootDocset->segment_files();

    if ( ret == 0 ) {
        m_status = CORPUS_STATUS_SEGMENTED;
    }

    return ret;
}

int Corpus::load_segment_files()
{
    std::string segment_rootdir = m_rootdir + "/" + m_name + "/segment";

    int ret = m_pRootDocset->load_segment_files(segment_rootdir);

    if ( ret == 0 ) {
        m_status = CORPUS_STATUS_SEGMENTED;
    }

    return ret;
}

int Corpus::save_segment_files() const
{
    std::string segment_rootdir = m_rootdir + "/" + m_name + "/segment";

    int ret = m_pRootDocset->save_segment_files(segment_rootdir);

    return ret;
}

ext: cc

max_stars_repo_name: uukuguy/everdata

max_issues_repo_name: uukuguy/everdata

max_forks_repo_name: uukuguy/everdata


text:
/**
 * Copyright 2021 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "backend/kernel_compiler/cpu/eigen/eigh_cpu_kernel.h"
#include <Eigen/Eigenvalues>
#include <type_traits>
#include "utils/ms_utils.h"

namespace mindspore {
namespace kernel {

namespace {
constexpr size_t kInputsNum = 2;
constexpr size_t kOutputsNum = 2;
constexpr size_t kDefaultShape = 1;
constexpr auto kAMatrixDimNum = 2;

}  // namespace
using Eigen::Dynamic;
using Eigen::EigenSolver;
using Eigen::Lower;
using Eigen::Map;
using Eigen::MatrixBase;
using Eigen::RowMajor;
using Eigen::Upper;

template <typename T>
using MatrixSquare = Eigen::Matrix<T, Dynamic, Dynamic, RowMajor>;

template <typename T>
using ComplexMatrixSquare = Eigen::Matrix<std::complex<T>, Dynamic, Dynamic, RowMajor>;

template <typename T>
void EighCPUKernel<T>::InitKernel(const CNodePtr &kernel_node) {
  dtype_ = AnfAlgo::GetInputDeviceDataType(kernel_node, 0);

  compute_eigen_vectors = AnfAlgo::GetNodeAttr<bool>(kernel_node, C_EIEH_VECTOR);

  auto A_shape = AnfAlgo::GetPrevNodeOutputInferShape(kernel_node, 0);
  CHECK_KERNEL_INPUTS_NUM(A_shape.size(), kAMatrixDimNum, AnfAlgo::GetCNodeName(kernel_node));

  if (A_shape.size() != kShape2dDims || A_shape[0] != A_shape[1]) {
    MS_LOG(EXCEPTION) << "wrong array shape, A should be a matrix, but got [" << A_shape[0] << " X " << A_shape[1]
                      << "]";
  }
  m_ = A_shape[0];
}

template <typename T>
void EighCPUKernel<T>::InitInputOutputSize(const CNodePtr &kernel_node) {
  CPUKernel::InitInputOutputSize(kernel_node);
  (void)workspace_size_list_.template emplace_back(m_ * m_ * sizeof(T));
}

template <typename T>
bool SolveSelfAdjointMatrix(const Map<MatrixSquare<T>> &A, Map<MatrixSquare<T>> *output, Map<MatrixSquare<T>> *outputv,
                            bool compute_eigen_vectors) {
  Eigen::SelfAdjointEigenSolver<MatrixSquare<T>> solver(A);
  output->noalias() = solver.eigenvalues();
  if (compute_eigen_vectors) {
    outputv->noalias() = solver.eigenvectors();
  }
  return true;
}

template <typename T>
bool SolveComplexMatrix(const Map<MatrixSquare<T>> &A, Map<MatrixSquare<T>> *output, Map<MatrixSquare<T>> *outputv,
                        bool compute_eigen_vectors) {
  Eigen::ComplexEigenSolver<MatrixSquare<T>> solver(A);
  output->noalias() = solver.eigenvalues();
  if (compute_eigen_vectors) {
    outputv->noalias() = solver.eigenvectors();
  }
  return true;
}

template <typename T>
bool EighCPUKernel<T>::Launch(const std::vector<AddressPtr> &inputs, const std::vector<AddressPtr> &workspace,
                              const std::vector<AddressPtr> &outputs) {
  CHECK_KERNEL_INPUTS_NUM(inputs.size(), kInputsNum, kernel_name_);
  CHECK_KERNEL_OUTPUTS_NUM(outputs.size(), kOutputsNum, kernel_name_);

  auto A_addr = reinterpret_cast<T *>(inputs[0]->addr);
  // is the Matrix a symmetric matrix(0, all, general matxi, -1 lower triangle, 1 upper triangle)
  auto symmetric_type = reinterpret_cast<bool *>(inputs[1]->addr);
  auto output_addr = reinterpret_cast<T *>(outputs[0]->addr);
  auto output_v_addr = reinterpret_cast<T *>(outputs[1]->addr);
  Map<MatrixSquare<T>> A(A_addr, m_, m_);
  Map<MatrixSquare<T>> A_(A_addr, m_, m_);
  Map<MatrixSquare<T>> output(output_addr, m_, 1);
  Map<MatrixSquare<T>> outputv(output_v_addr, m_, m_);
  // selfadjoint matrix
  if (*symmetric_type) {
    A_ = A.template selfadjointView<Lower>();
  } else {
    A_ = A.template selfadjointView<Upper>();
  }
  // Real scalar eigen solver
  if constexpr (std::is_same_v<T, float>) {
    SolveSelfAdjointMatrix(A_, &output, &outputv, compute_eigen_vectors);
  } else if constexpr (std::is_same_v<T, double>) {
    SolveSelfAdjointMatrix(A_, &output, &outputv, compute_eigen_vectors);
  } else {
    // complex eigen solver
    SolveComplexMatrix(A_, &output, &outputv, compute_eigen_vectors);
  }
  return true;
}
}  // namespace kernel
}  // namespace mindspore

max_stars_repo_name: LaiYongqiang/mindspore

max_issues_repo_name: LaiYongqiang/mindspore

max_forks_repo_name: LaiYongqiang/mindspore


text:
#ifndef TARJAN_SCC_HPP
#define TARJAN_SCC_HPP

#include "extractor/node_based_edge.hpp"
#include "extractor/query_node.hpp"
#include "util/deallocating_vector.hpp"
#include "util/percent.hpp"
#include "util/typedefs.hpp"

#include "util/integer_range.hpp"
#include "util/log.hpp"
#include "util/std_hash.hpp"
#include "util/timing_util.hpp"

#include "osrm/coordinate.hpp"
#include <boost/assert.hpp>
#include <cstdint>

#include <algorithm>
#include <climits>
#include <memory>
#include <stack>
#include <vector>

namespace osrm
{
namespace extractor
{

template <typename GraphT> class TarjanSCC
{
    struct TarjanStackFrame
    {
        explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
        NodeID v;
        NodeID parent;
    };

    struct TarjanNode
    {
        TarjanNode() : index(SPECIAL_NODEID), low_link(SPECIAL_NODEID), on_stack(false) {}
        unsigned index;
        unsigned low_link;
        bool on_stack;
    };

    std::vector<unsigned> components_index;
    std::vector<NodeID> component_size_vector;
    const GraphT &m_graph;
    std::size_t size_one_counter;

  public:
    TarjanSCC(const GraphT &graph)
        : components_index(graph.GetNumberOfNodes(), SPECIAL_NODEID), m_graph(graph),
          size_one_counter(0)
    {
        BOOST_ASSERT(m_graph.GetNumberOfNodes() > 0);
    }

    void Run()
    {
        TIMER_START(SCC_RUN);
        const NodeID max_node_id = m_graph.GetNumberOfNodes();

        // The following is a hack to distinguish between stuff that happens
        // before the recursive call and stuff that happens after
        std::stack<TarjanStackFrame> recursion_stack;
        // true = stuff before, false = stuff after call
        std::stack<NodeID> tarjan_stack;
        std::vector<TarjanNode> tarjan_node_list(max_node_id);
        unsigned component_index = 0, size_of_current_component = 0;
        unsigned large_component_count = 0;
        unsigned index = 0;
        std::vector<bool> processing_node_before_recursion(max_node_id, true);
        for (const NodeID node : util::irange(0u, max_node_id))
        {
            if (SPECIAL_NODEID == components_index[node])
            {
                recursion_stack.emplace(TarjanStackFrame(node, node));
            }

            while (!recursion_stack.empty())
            {
                TarjanStackFrame currentFrame = recursion_stack.top();
                const NodeID u = currentFrame.parent;
                const NodeID v = currentFrame.v;
                recursion_stack.pop();

                const bool before_recursion = processing_node_before_recursion[v];

                if (before_recursion && tarjan_node_list[v].index != UINT_MAX)
                {
                    continue;
                }

                if (before_recursion)
                {
                    // Mark frame to handle tail of recursion
                    recursion_stack.emplace(currentFrame);
                    processing_node_before_recursion[v] = false;

                    // Mark essential information for SCC
                    tarjan_node_list[v].index = index;
                    tarjan_node_list[v].low_link = index;
                    tarjan_stack.push(v);
                    tarjan_node_list[v].on_stack = true;
                    ++index;

                    for (const auto current_edge : m_graph.GetAdjacentEdgeRange(v))
                    {
                        const auto vprime = m_graph.GetTarget(current_edge);

                        if (SPECIAL_NODEID == tarjan_node_list[vprime].index)
                        {
                            recursion_stack.emplace(TarjanStackFrame(vprime, v));
                        }
                        else
                        {
                            if (tarjan_node_list[vprime].on_stack &&
                                tarjan_node_list[vprime].index < tarjan_node_list[v].low_link)
                            {
                                tarjan_node_list[v].low_link = tarjan_node_list[vprime].index;
                            }
                        }
                    }
                }
                else
                {
                    processing_node_before_recursion[v] = true;
                    tarjan_node_list[u].low_link =
                        std::min(tarjan_node_list[u].low_link, tarjan_node_list[v].low_link);
                    // after recursion, lets do cycle checking
                    // Check if we found a cycle. This is the bottom part of the recursion
                    if (tarjan_node_list[v].low_link == tarjan_node_list[v].index)
                    {
                        NodeID vprime;
                        do
                        {
                            vprime = tarjan_stack.top();
                            tarjan_stack.pop();
                            tarjan_node_list[vprime].on_stack = false;
                            components_index[vprime] = component_index;
                            ++size_of_current_component;
                        } while (v != vprime);

                        component_size_vector.emplace_back(size_of_current_component);

                        if (size_of_current_component > 1000)
                        {
                            ++large_component_count;
                            util::Log(logDEBUG) << "large component [" << component_index
                                                << "]=" << size_of_current_component;
                        }

                        ++component_index;
                        size_of_current_component = 0;
                    }
                }
            }
        }

        TIMER_STOP(SCC_RUN);
        util::Log() << "Found " << component_index << " SCC (" << large_component_count
                    << " large, " << (component_index - large_component_count) << " small)";
        util::Log() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";

        size_one_counter = std::count_if(component_size_vector.begin(),
                                         component_size_vector.end(),
                                         [](unsigned value) { return 1 == value; });
    }

    std::size_t GetNumberOfComponents() const { return component_size_vector.size(); }

    std::size_t GetSizeOneCount() const { return size_one_counter; }

    unsigned GetComponentSize(const unsigned component_id) const
    {
        return component_size_vector[component_id];
    }

    unsigned GetComponentID(const NodeID node) const { return components_index[node]; }
};
} // namespace extractor
} // namespace osrm

#endif /* TARJAN_SCC_HPP */


text:
#include "FSResourcePackage.h"

#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>

using namespace boost::filesystem;

namespace rocket { namespace resource {

FSResourcePackage::FSResourcePackage(std::string const& directoryPath) :
		directoryPath(directoryPath) {}

bool FSResourcePackage::fileExistsImpl(std::string const& file) const {
	path p(directoryPath + "/" + file);
	return exists(p);
}

std::shared_ptr<std::istream> FSResourcePackage::openFileImpl(std::string const& file) {
	path p(directoryPath + "/" + file);
	return std::make_shared<ifstream>(p, std::ios_base::binary | std::ios_base::in);
}

}}


text:
/****************************************************************************
 *  hipipe library
 *  Copyright (c) 2017, Cognexa Solutions s.r.o.
 *  Copyright (c) 2018, Iterait a.s.
 *  Author(s) Filip Matzner
 *
 *  This file is distributed under the MIT License.
 *  See the accompanying file LICENSE.txt for the complete license agreement.
 ****************************************************************************/
/// \defgroup CSV CSV parser.

#include <hipipe/core/csv.hpp>

#include <boost/algorithm/string.hpp>
#include <range/v3/algorithm/find_first_of.hpp>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/drop.hpp>
#include <range/v3/view/move.hpp>

#include <array>
#include <cctype>
#include <climits>
#include <deque>
#include <experimental/filesystem>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <vector>

namespace hipipe {

namespace rg = ranges;
namespace rgv = ranges::views;

// Read and discard blank characters (similar to std::ws, but uses std::isblank).
//
// This is a stream manipulator.
static std::istream& blanks(std::istream& in)
{
    while (std::isblank(in.peek())) in.get();
    return in;
}

std::tuple<std::string, bool> csv_istream_range::parse_field()
{
    std::string field;
    char c;
    while (in_->get(c)) {
        if (c == separator_) {
            return {std::move(field), true};
        } else if (c == '\n') {
            return {std::move(field), false};
        }
        field.push_back(c);
    }
    return {std::move(field), false};
}

void csv_istream_range::next()
{
    if (!in_->good() || row_position_ == RowPosition::Last) {
        row_position_ = RowPosition::End;
        return;
    }

    // temporarily set badbit exception mask
    auto orig_exceptions = in_->exceptions();
    in_->exceptions(orig_exceptions | std::istream::badbit);

    row_.clear();
    bool has_next = true;
    while (has_next && *in_ >> blanks) {
        std::string field;
        // process quoted fields
        if (in_->peek() == quote_) {
            *in_ >> std::quoted(field, quote_, escape_);
            if (in_->fail()) throw std::ios_base::failure{"Error while reading CSV field."};
            std::tie(std::ignore, has_next) = parse_field();
        }
        // process unquoted fields
        else {
            std::tie(field, has_next) = parse_field();
            boost::trim(field);
        }
        row_.push_back(std::move(field));
    }

    // detect whether end of file is reached
    *in_ >> std::ws;
    in_->peek();
    if (!in_->good()) {
        row_position_ = RowPosition::Last;
    }

    // reset exception mask
    in_->exceptions(orig_exceptions);
}

csv_istream_range::csv_istream_range(
  std::istream& in,
  char separator,
  char quote,
  char escape)
  : in_{&in}
  , separator_{separator}
  , quote_{quote}
  , escape_{escape}
{
    in_->peek();
    next();
}

dataframe read_csv(
  std::istream& in,
  int drop,
  bool has_header,
  char separator,
  char quote,
  char escape)
{
    // header
    std::vector<std::string> header;
    // data
    std::vector<std::vector<std::string>> data;
    // load csv line by line
    auto csv_rows =
      csv_istream_range(in, separator, quote, escape)
      | rgv::drop(drop)
      | rgv::move;
    auto csv_row_it = rg::begin(csv_rows);
    // load header if requested
    std::size_t n_cols = -1;
    if (has_header) {
        if (csv_row_it == rg::end(csv_rows)) {
            throw std::ios_base::failure{"There has to be at least the header row."};
        }
        std::vector<std::string> csv_row = *csv_row_it;
        n_cols = rg::size(csv_row);
        header = std::move(csv_row);
        data.resize(n_cols);
        ++csv_row_it;
    }
    // load data
    for (std::size_t i = 0; csv_row_it != rg::end(csv_rows); ++csv_row_it, ++i) {
        std::vector<std::string> csv_row = *csv_row_it;
        // sanity check row size
        if (i == 0) {
            if (has_header) {
                if (rg::size(csv_row) != n_cols) {
                    throw std::ios_base::failure{"The first row must have the same "
                                                 "length as the header."};
                }
            } else {
                n_cols = rg::size(csv_row);
                data.resize(n_cols);
            }
        } else {
            if (rg::size(csv_row) != n_cols) {
                throw std::ios_base::failure{"Row " + std::to_string(i)
                                             + " has a different length "
                                             + "(has: " + std::to_string(rg::size(csv_row))
                                             + " , expected: " + std::to_string(n_cols)
                                             + ")."};
            }
        }
        // store columns
        for (std::size_t j = 0; j < rg::size(csv_row); ++j) {
            data[j].push_back(std::move(csv_row[j]));
        }
    }
    return {std::move(data), std::move(header)};
}

dataframe read_csv(
  const std::experimental::filesystem::path& file,
  int drop,
  bool header,
  char separator,
  char quote,
  char escape)
{
    std::ifstream fin{file};
    if (!fin) {
        throw std::ios_base::failure{"Cannot open " + file.string() + " CSV file for reading."};
    }
    return read_csv(fin, drop, header, separator, quote, escape);
}

static bool trimmable(const std::string& str)
{
    if (str.length() == 0) return false;
    return std::isspace(str.front()) || std::isspace(str.back());
}

std::ostream& write_csv_row(
  std::ostream& out,
  const std::vector<std::string>& row,
  char separator,
  char quote,
  char escape)
{
    // temporarily set badbit exception mask
    auto orig_exceptions = out.exceptions();
    out.exceptions(orig_exceptions | std::ostream::badbit);

    for (std::size_t i = 0; i < rg::size(row); ++i) {
        const std::string& field = row[i];
        // output quoted string if it contains separator, double quote, newline or
        // starts or ends with a whitespace
        std::array<char, 3> must_quote = {separator, quote, '\n'};
        if (rg::find_first_of(field, must_quote) != rg::end(field) || trimmable(field)) {
            out << std::quoted(field, quote, escape);
        } else {
            out << field;
        }

        // output separator or newline
        if (i + 1 < rg::size(row)) out << separator;
        else out << '\n';
    }

    out.exceptions(orig_exceptions);
    return out;
}

std::ostream& write_csv(
  std::ostream& out,
  const dataframe& df,
  char separator,
  char quote,
  char escape)
{
    write_csv_row(out, df.header(), separator, quote, escape);
    for (auto&& row : df.raw_rows()) {
        write_csv_row(out, rg::to_vector(row), separator, quote, escape);
    }
    return out;
}

void write_csv(
  const std::experimental::filesystem::path& file,
  const dataframe& df,
  char separator,
  char quote,
  char escape)
{
    std::ofstream fout{file};
    if (!fout) {
        throw std::ios_base::failure{"Cannot open " + file.string() + " CSV file for writing."};
    }
    write_csv(fout, df, separator, quote, escape);
}

}  // namespace hipipe

max_stars_repo_name: iterait/hipipe

max_issues_repo_name: iterait/hipipe

max_forks_repo_name: iterait/hipipe


text:
// Boost.Function library examples

// Copyright (C) 2001 Doug Gregor (gregod@cs.rpi.edu)
//
// Permission to copy, use, sell and distribute this software is granted
// provided this copyright notice appears in all copies.
// Permission to modify the code and to distribute modified code is granted
// provided this copyright notice appears in all copies, and a notice
// that the code was modified is included with the copyright notice.
//
// This software is provided "as is" without express or implied warranty,
// and with no claim as to its suitability for any purpose.

// For more information, see http://www.boost.org

#include <iostream>
#include <boost/function.hpp>

struct int_div {
  float operator()(int x, int y) const { return ((float)x)/y; };
};

int
main()
{
  boost::function<float, int, int> f;
  f = int_div();

  std::cout << f(5, 3) << std::endl; // 1.66667

  return 0;
}


text:
/*************************************************************************
 * Dicomifier - Copyright (C) Universite de Strasbourg
 * Distributed under the terms of the CeCILL-B license, as published by
 * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
 * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
 * for details.
 ************************************************************************/

#define BOOST_TEST_MODULE ModuleDicomifierException
#include <boost/test/unit_test.hpp>

#include "core/DicomifierException.h"

/******************************* TEST Nominal **********************************/
/**
 * Nominal test case: Throw
 */
BOOST_AUTO_TEST_CASE(Throw)
{
    BOOST_REQUIRE_THROW(throw dicomifier::DicomifierException("Error"),
                        dicomifier::DicomifierException);
}

/******************************* TEST Nominal **********************************/
/**
 * Nominal test case: Message
 */
BOOST_AUTO_TEST_CASE(Check_Message)
{
    try
    {
        throw dicomifier::DicomifierException("Error");
    }
    catch (dicomifier::DicomifierException& exc)
    {
        BOOST_CHECK_EQUAL(exc.what(), "Error");
    }
}

max_stars_repo_name: fgrelard/dicomifier

max_issues_repo_name: fgrelard/dicomifier

max_forks_repo_name: fgrelard/dicomifier