<commit_before>/*

Copyright (c) 2006, 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.

*/

#ifndef NODE_HPP
#define NODE_HPP

#include <algorithm>
#include <map>
#include <set>

#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/node_id.hpp>
#include <libtorrent/kademlia/msg.hpp>
#include <libtorrent/kademlia/find_data.hpp>

#include <libtorrent/io.hpp>
#include <libtorrent/session_settings.hpp>
#include <libtorrent/assert.hpp>
#include <libtorrent/thread.hpp>

#include <boost/cstdint.hpp>
#include <boost/optional.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/ref.hpp>
#include <boost/optional.hpp>

#include "libtorrent/socket.hpp"

namespace libtorrent {

	namespace aux { struct session_impl; }
	struct session_status;

}

namespace libtorrent { namespace dht
{

#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DECLARE_LOG(node);
#endif

class traversal_algorithm;

struct key_desc_t
{
	char const* name;
	int type;
	int size;
	int flags;

	enum { optional = 1};
};

bool TORRENT_EXPORT verify_message(lazy_entry const* msg, key_desc_t const desc[], lazy_entry const* ret[]
	, int size , char* error, int error_size);

// this is the entry for every peer
// the timestamp is there to make it possible
// to remove stale peers
struct peer_entry
{
	tcp::endpoint addr;
	ptime added;
};

// this is a group. It contains a set of group members
struct torrent_entry
{
	std::set<peer_entry> peers;
};

// this is the entry for a torrent that has been published
// in the DHT.
struct search_torrent_entry
{
	// the tags of the torrent. The key of
	// this entry is the sha-1 hash of one of
	// these tags. The counter is the number of
	// times a tag has been included in a publish
	// call. The counters are periodically
	// decremented by a factor, so that the
	// popularity ratio between the tags is
	// maintained. The decrement is rounded down.
	std::map<std::string, int> tags;

	// this is the sum of all values in the tags
	// map. It is only an optimization to avoid
	// recalculating it constantly
	int total_tag_points;

	// the name of the torrent
	std::map<std::string, int> name;
	int total_name_points;

	// increase the popularity counters for this torrent
	void publish(std::string const& name, char const* in_tags[], int num_tags);

	// return a score of how well this torrent matches
	// the given set of tags. Each word in the string
	// (separated by a space) is considered a tag.
	// tags with 2 letters or fewer are ignored
	int match(char const* tags[], int num_tags) const;

	// this is called once every hour, and will
	// decrement the popularity counters of the
	// tags. Returns true if this entry should
	// be deleted
	bool tick();

	void get_name(std::string& t) const;
	void get_tags(std::string& t) const;
};

inline bool operator<(peer_entry const& lhs, peer_entry const& rhs)
{
	return lhs.addr.address() == rhs.addr.address()
		? lhs.addr.port() < rhs.addr.port()
		: lhs.addr.address() < rhs.addr.address();
}

struct null_type {};

class announce_observer : public observer
{
public:
	announce_observer(boost::intrusive_ptr<traversal_algorithm> const& algo)
		: observer(algo)
	{}

	void reply(msg const&) { m_done = true; }
};

struct count_peers
{
	int& count;
	count_peers(int& c): count(c) {}
	void operator()(std::pair<libtorrent::dht::node_id
		, libtorrent::dht::torrent_entry> const& t)
	{
		count += t.second.peers.size();
	}
};

class node_impl : boost::noncopyable
{
typedef std::map<node_id, torrent_entry> table_t;
typedef std::map<std::pair<node_id, sha1_hash>, search_torrent_entry> search_table_t;
public:
	node_impl(libtorrent::aux::session_impl& ses
		, bool (*f)(void*, entry const&, udp::endpoint const&, int)
		, dht_settings const& settings, boost::optional<node_id> nid
		, void* userdata);

	virtual ~node_impl() {}

	void refresh(node_id const& id, find_data::nodes_callback const& f);
	void bootstrap(std::vector<udp::endpoint> const& nodes
		, find_data::nodes_callback const& f);
	void add_router_node(udp::endpoint router);

	void unreachable(udp::endpoint const& ep);
	void incoming(msg const& m);

	int num_torrents() const { return m_map.size(); }
	int num_peers() const
	{
		int ret = 0;
		std::for_each(m_map.begin(), m_map.end(), count_peers(ret));
		return ret;
	}

	void refresh();
	void refresh_bucket(int bucket);
	int bucket_size(int bucket);

	typedef routing_table::iterator iterator;

	iterator begin() const { return m_table.begin(); }
	iterator end() const { return m_table.end(); }

	node_id const& nid() const { return m_id; }

	boost::tuple<int, int> size() const{ return m_table.size(); }
	size_type num_global_nodes() const
	{ return m_table.num_global_nodes(); }

	int data_size() const { return int(m_map.size()); }

#ifdef TORRENT_DHT_VERBOSE_LOGGING
	void print_state(std::ostream& os) const
	{ m_table.print_state(os); }
#endif

	void announce(sha1_hash const& info_hash, int listen_port
		, boost::function<void(std::vector<tcp::endpoint> const&)> f);

	bool verify_token(std::string const& token, char const* info_hash
		, udp::endpoint const& addr);

	std::string generate_token(udp::endpoint const& addr, char const* info_hash);

	// the returned time is the delay until connection_timeout()
	// should be called again the next time
	time_duration connection_timeout();
	time_duration refresh_timeout();

	// generates a new secret number used to generate write tokens
	void new_write_key();

	// pings the given node, and adds it to
	// the routing table if it respons and if the
	// bucket is not full.
	void add_node(udp::endpoint node);

	void replacement_cache(bucket_t& nodes) const
	{ m_table.replacement_cache(nodes); }

	int branch_factor() const { return m_settings.search_branching; }

	void add_traversal_algorithm(traversal_algorithm* a)
	{
		mutex_t::scoped_lock l(m_mutex);
		m_running_requests.insert(a);
	}

	void remove_traversal_algorithm(traversal_algorithm* a)
	{
		mutex_t::scoped_lock l(m_mutex);
		m_running_requests.erase(a);
	}

	void status(libtorrent::session_status& s);

protected:
	// is called when a find data request is received. Should
	// return false if the data is not stored on this node. If
	// the data is stored, it should be serialized into 'data'.
	bool lookup_peers(sha1_hash const& info_hash, entry& reply) const;
	bool lookup_torrents(sha1_hash const& target, entry& reply
		, char* tags) const;

	dht_settings const& m_settings;

	// the maximum number of peers to send in a get_peers
	// reply. Ordinary trackers usually limit this to 50.
	// 50 => 6 * 50 = 250 bytes + packet overhead
	int m_max_peers_reply;

private:
	typedef libtorrent::mutex mutex_t;
	mutex_t m_mutex;

	// this list must be destructed after the rpc manager
	// since it might have references to it
	std::set<traversal_algorithm*> m_running_requests;

	void incoming_request(msg const& h, entry& e);

	node_id m_id;

public:
	routing_table m_table;
	rpc_manager m_rpc;

private:
	table_t m_map;
	search_table_t m_search_map;

	ptime m_last_tracker_tick;

	// secret random numbers used to create write tokens
	int m_secret[2];

	libtorrent::aux::session_impl& m_ses;
	bool (*m_send)(void*, entry const&, udp::endpoint const&, int);
	void* m_userdata;
};

} } // namespace libtorrent::dht

#endif // NODE_HPP

<commit_msg>dht fix<commit_after>/*

Copyright (c) 2006, 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.

*/

#ifndef NODE_HPP
#define NODE_HPP

#include <algorithm>
#include <map>
#include <set>

#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/node_id.hpp>
#include <libtorrent/kademlia/msg.hpp>
#include <libtorrent/kademlia/find_data.hpp>

#include <libtorrent/io.hpp>
#include <libtorrent/session_settings.hpp>
#include <libtorrent/assert.hpp>
#include <libtorrent/thread.hpp>

#include <boost/cstdint.hpp>
#include <boost/optional.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/ref.hpp>
#include <boost/optional.hpp>

#include "libtorrent/socket.hpp"

namespace libtorrent {

	namespace aux { struct session_impl; }
	struct session_status;

}

namespace libtorrent { namespace dht
{

#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DECLARE_LOG(node);
#endif

class traversal_algorithm;

struct key_desc_t
{
	char const* name;
	int type;
	int size;
	int flags;

	enum { optional = 1};
};

bool TORRENT_EXPORT verify_message(lazy_entry const* msg, key_desc_t const desc[], lazy_entry const* ret[]
	, int size , char* error, int error_size);

// this is the entry for every peer
// the timestamp is there to make it possible
// to remove stale peers
struct peer_entry
{
	tcp::endpoint addr;
	ptime added;
};

// this is a group. It contains a set of group members
struct torrent_entry
{
	std::set<peer_entry> peers;
};

// this is the entry for a torrent that has been published
// in the DHT.
struct search_torrent_entry
{
	search_torrent_entry(): total_tag_points(0), total_name_points(0) {}

	// the tags of the torrent. The key of
	// this entry is the sha-1 hash of one of
	// these tags. The counter is the number of
	// times a tag has been included in a publish
	// call. The counters are periodically
	// decremented by a factor, so that the
	// popularity ratio between the tags is
	// maintained. The decrement is rounded down.
	std::map<std::string, int> tags;

	// this is the sum of all values in the tags
	// map. It is only an optimization to avoid
	// recalculating it constantly
	int total_tag_points;

	// the name of the torrent
	std::map<std::string, int> name;
	int total_name_points;

	// increase the popularity counters for this torrent
	void publish(std::string const& name, char const* in_tags[], int num_tags);

	// return a score of how well this torrent matches
	// the given set of tags. Each word in the string
	// (separated by a space) is considered a tag.
	// tags with 2 letters or fewer are ignored
	int match(char const* tags[], int num_tags) const;

	// this is called once every hour, and will
	// decrement the popularity counters of the
	// tags. Returns true if this entry should
	// be deleted
	bool tick();

	void get_name(std::string& t) const;
	void get_tags(std::string& t) const;
};

inline bool operator<(peer_entry const& lhs, peer_entry const& rhs)
{
	return lhs.addr.address() == rhs.addr.address()
		? lhs.addr.port() < rhs.addr.port()
		: lhs.addr.address() < rhs.addr.address();
}

struct null_type {};

class announce_observer : public observer
{
public:
	announce_observer(boost::intrusive_ptr<traversal_algorithm> const& algo)
		: observer(algo)
	{}

	void reply(msg const&) { m_done = true; }
};

struct count_peers
{
	int& count;
	count_peers(int& c): count(c) {}
	void operator()(std::pair<libtorrent::dht::node_id
		, libtorrent::dht::torrent_entry> const& t)
	{
		count += t.second.peers.size();
	}
};

class node_impl : boost::noncopyable
{
typedef std::map<node_id, torrent_entry> table_t;
typedef std::map<std::pair<node_id, sha1_hash>, search_torrent_entry> search_table_t;
public:
	node_impl(libtorrent::aux::session_impl& ses
		, bool (*f)(void*, entry const&, udp::endpoint const&, int)
		, dht_settings const& settings, boost::optional<node_id> nid
		, void* userdata);

	virtual ~node_impl() {}

	void refresh(node_id const& id, find_data::nodes_callback const& f);
	void bootstrap(std::vector<udp::endpoint> const& nodes
		, find_data::nodes_callback const& f);
	void add_router_node(udp::endpoint router);

	void unreachable(udp::endpoint const& ep);
	void incoming(msg const& m);

	int num_torrents() const { return m_map.size(); }
	int num_peers() const
	{
		int ret = 0;
		std::for_each(m_map.begin(), m_map.end(), count_peers(ret));
		return ret;
	}

	void refresh();
	void refresh_bucket(int bucket);
	int bucket_size(int bucket);

	typedef routing_table::iterator iterator;

	iterator begin() const { return m_table.begin(); }
	iterator end() const { return m_table.end(); }

	node_id const& nid() const { return m_id; }

	boost::tuple<int, int> size() const{ return m_table.size(); }
	size_type num_global_nodes() const
	{ return m_table.num_global_nodes(); }

	int data_size() const { return int(m_map.size()); }

#ifdef TORRENT_DHT_VERBOSE_LOGGING
	void print_state(std::ostream& os) const
	{ m_table.print_state(os); }
#endif

	void announce(sha1_hash const& info_hash, int listen_port
		, boost::function<void(std::vector<tcp::endpoint> const&)> f);

	bool verify_token(std::string const& token, char const* info_hash
		, udp::endpoint const& addr);

	std::string generate_token(udp::endpoint const& addr, char const* info_hash);

	// the returned time is the delay until connection_timeout()
	// should be called again the next time
	time_duration connection_timeout();
	time_duration refresh_timeout();

	// generates a new secret number used to generate write tokens
	void new_write_key();

	// pings the given node, and adds it to
	// the routing table if it respons and if the
	// bucket is not full.
	void add_node(udp::endpoint node);

	void replacement_cache(bucket_t& nodes) const
	{ m_table.replacement_cache(nodes); }

	int branch_factor() const { return m_settings.search_branching; }

	void add_traversal_algorithm(traversal_algorithm* a)
	{
		mutex_t::scoped_lock l(m_mutex);
		m_running_requests.insert(a);
	}

	void remove_traversal_algorithm(traversal_algorithm* a)
	{
		mutex_t::scoped_lock l(m_mutex);
		m_running_requests.erase(a);
	}

	void status(libtorrent::session_status& s);

protected:
	// is called when a find data request is received. Should
	// return false if the data is not stored on this node. If
	// the data is stored, it should be serialized into 'data'.
	bool lookup_peers(sha1_hash const& info_hash, entry& reply) const;
	bool lookup_torrents(sha1_hash const& target, entry& reply
		, char* tags) const;

	dht_settings const& m_settings;

	// the maximum number of peers to send in a get_peers
	// reply. Ordinary trackers usually limit this to 50.
	// 50 => 6 * 50 = 250 bytes + packet overhead
	int m_max_peers_reply;

private:
	typedef libtorrent::mutex mutex_t;
	mutex_t m_mutex;

	// this list must be destructed after the rpc manager
	// since it might have references to it
	std::set<traversal_algorithm*> m_running_requests;

	void incoming_request(msg const& h, entry& e);

	node_id m_id;

public:
	routing_table m_table;
	rpc_manager m_rpc;

private:
	table_t m_map;
	search_table_t m_search_map;

	ptime m_last_tracker_tick;

	// secret random numbers used to create write tokens
	int m_secret[2];

	libtorrent::aux::session_impl& m_ses;
	bool (*m_send)(void*, entry const&, udp::endpoint const&, int);
	void* m_userdata;
};

} } // namespace libtorrent::dht

#endif // NODE_HPP

<|endoftext|>


<commit_before>/*
Copyright (c) 2016-2017 stoyan shopov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef DISASSEMBLY_HXX
#define DISASSEMBLY_HXX

#include <QFile>
#include <QVector>
#include <QPair>
#include <QRegExp>
#include <QDebug>
#include <QMessageBox>
#include <stdint.h>
#include "memory.hxx"
#include "target.hxx"
#include "util.hxx"

#include <platform.h>
#include <capstone/capstone.h>

enum
{
	DISASSEMBLY_AROUND_ADDRESS_CONTEXT_LINE_COUNT	= 100,
};

class Disassembly
{
private:
	csh cs_handle;
	Memory	memory;
	QByteArray	disassembly_text;
	QVector<QPair<uint32_t /* address */, int /* index in disassembly text */> > index_table;
	int indexOfAddress(uint32_t address)
	{
		int l = 0, h = index_table.size() - 1, m;
		while (l <= h)
		{
			m = (l + h) >> 1;
			if (index_table.at(m).first == address)
				break;
			if (index_table.at(m).first < address)
				l = m + 1;
			else
				h = m - 1;
		}
		if (l > h)
			return -1;
		return m;
	}
	QString disassembleBytes(const QByteArray & data, uint32_t address)
	{
		QString dis;
		int count;
		if (data.size() != 2 && data.size() != 4)
			Util::panic();
		cs_insn		* insn;

		if ((count = cs_disasm(cs_handle, (const uint8_t *) data.constData(), data.length(), address, 0, & insn) == 1) && insn->size == data.size())
			dis = QString("%1:\t%2\t%3\t\t%4")
		                                  .arg(insn->address, 8, 16, QChar('0'))
		                                  .arg(QString(QByteArray((const char *) insn->bytes, insn->size).toHex()))
		                                  .arg(insn->mnemonic).arg(insn->op_str);
		cs_free(insn, count);
		return dis;
	}
public:
	Disassembly(QByteArray disassembly, const Memory & memory)
	{
		int i = 0, x;
		bool ok;
		QRegExp rx("^\\s*(\\w+):");
		this->memory = memory;
		if (cs_open(CS_ARCH_ARM, CS_MODE_THUMB, & cs_handle))
		{
			QMessageBox::critical(0, "failed to initialize the disassembly library",
					      "failed to initialize the disassembly library\n\n"
					      "this is a fatal error, and the troll will now abort");
			Util::panic();
		}
		//return;

		disassembly_text = disassembly;
		while (i < disassembly_text.size())
		{
			QString s(disassembly_text.mid(i, (x = disassembly_text.indexOf('\n', i)) - i));
			if (rx.indexIn(s) != -1)
			{
				uint32_t address = rx.cap(1).toUInt(& ok, 16);
				if (ok)
					index_table << QPair<uint32_t, int>(address, i);
			}
			if (x == -1)
				break;
			i = x + 1;
		}
		for (i = 1; i < index_table.size(); i ++)
			if (index_table.at(i).first <= index_table.at(i - 1).first)
				Util::panic();
	}
	/*! \todo	reading target memory here with	'readBytes()' is ***slow*** - maybe fix this */
	QList<QPair<uint32_t, QString> > disassemblyAroundAddress(uint32_t address, class Target * target, int * line_for_address = 0)
	{
		QString x;
		QList<QPair<uint32_t, QString> > dis;
		QPair<uint32_t, QString> t;
		uint32_t l, h, i = 0;
		QByteArray data;
		if (line_for_address)
			* line_for_address = -1;
		data = target->readBytes(address, 4, true);
		if (!data.size())
		{
			dis.push_back(QPair<uint32_t, QString> (address, QString("<<< cannot read memory at address $%1 >>>").arg(address, 8, 16, QChar('0'))));
			return dis;
		}
		if (!(x = disassembleBytes(data.left(2), address)).isEmpty())
			h = address + 2, dis.push_back(QPair<uint32_t, QString> (address, x));
		else if (!(x = disassembleBytes(data, address)).isEmpty())
			h = address + 4, dis.push_back(QPair<uint32_t, QString> (address, x));
		else
		{
			dis.push_back(QPair<uint32_t, QString> (address, QString("<<< cannot disassemble bytes at address $%1 >>>").arg(address, 8, 16, QChar('0'))));
			return dis;
		}
		l = address;
		for (i = 0; i < DISASSEMBLY_AROUND_ADDRESS_CONTEXT_LINE_COUNT; i ++)
		{
			l -= 4;
			data = target->readBytes(l, 4, true);
			if (!data.size())
			{
				dis.push_front(QPair<uint32_t, QString> (l, QString("<<< cannot read memory at address $%1 >>>").arg(l, 8, 16, QChar('0'))));
				return dis;
			}
			if (!(x = disassembleBytes(data.right(2), l + 2)).isEmpty())
				l += 2, t.first = l, t.second = x, dis.push_front(t);
			else if (!(x = disassembleBytes(data, l)).isEmpty())
				t.first = l, t.second = x, dis.push_front(t);
			else
				l += 2,t.first = l + 2, t.second = QString("<<< cannot disassemble bytes at address $%1 >>>").arg(l, 8, 16, QChar('0')),  dis.push_front(t);

			t.first = h;
			data = target->readBytes(h, 4, true);
			if (!data.size())
			{
				dis.push_back(QPair<uint32_t, QString> (h, QString("<<< cannot read memory at address $%1 >>>").arg(h, 8, 16, QChar('0'))));
				return dis;
			}
			if (!(x = disassembleBytes(data, h)).isEmpty())
				h += 4, t.second = x, dis.push_back(t);
			else if (!(x = disassembleBytes(data.left(2), h)).isEmpty())
				h += 2, t.second = x, dis.push_back(t);
			else
				h += 2, t.second = QString("<<< cannot disassemble bytes at address $%1 >>>").arg(h, 8, 16, QChar('0')), dis.push_back(t);
		}
		if (line_for_address)
			* line_for_address = i;
		return dis;
	}
	QList<QPair<uint32_t /* address */, QString /* disassembly */> > disassemblyForRange(uint32_t start, uint32_t end)
	{
		QList<QPair<uint32_t , QString > > dis;
		int i;
		while (start < end)
		{
			i = indexOfAddress(start);

			if (i == -1 || i == /* not really exact, but doesn't matter anyway */ index_table.size() - 1)
			{
				cs_insn		* insn;
				auto x = memory.data(start, 4);
				i = cs_disasm(cs_handle, (const uint8_t *) x.constData(), x.length(), start, 0, & insn);

				if (!i)
					return dis << QPair<uint32_t, QString>(start, QString("<<< no disassembly for address $%1 >>>").arg(start, 8, 16, QChar('0')));
				dis << QPair<uint32_t , QString >(insn->address, QString("%1:\t%2\t%3\t\t%4")
								  .arg(insn->address, 8, 16, QChar('0'))
								  .arg(QString(QByteArray((const char *) insn->bytes, insn->size).toHex()))
								  .arg(insn->mnemonic).arg(insn->op_str));
				start += insn->size;
				cs_free(insn, i);
			}
			else
			{
				dis << QPair<uint32_t , QString >(start, disassembly_text.mid(index_table.at(i).second, disassembly_text.indexOf('\n', index_table.at(i).second) - index_table.at(i).second ));
				start = index_table.at(++ i).first;
			}
		}
		return dis;
	}
	void disassemble(const uint8_t * bytes, int length, uint32_t address)
	{
		csh handle;
		cs_insn * insn;
		int i;
		size_t count;
		cs_err err;

			err = cs_open(CS_ARCH_ARM, CS_MODE_THUMB, &handle);
			if (err)
			{
				printf("Failed on cs_open() with error returned: %u\n", err);
				return;
			}

			count = cs_disasm(handle, bytes, length, address, 0, & insn);
			if (count)
			{
				size_t j;

				//print_string_hex(platforms[i].code, platforms[i].size);
				printf("Disasm:\n");

				for (j = 0; j < count; j++) {
					fprintf(stderr, "%08x"  ":\t%s\t\t%s\n",
					       (uint32_t) insn[j].address, insn[j].mnemonic, insn[j].op_str);
				}

				// print out the next offset, after the last insn
				printf("0x%08x"  ":\n", (uint32_t) insn[j-1].address + insn[j-1].size);

				// free memory allocated by cs_disasm()
				cs_free(insn, count);
			}

			printf("\n");

			cs_close(&handle);
	}
};

#endif // DISASSEMBLY_HXX
<commit_msg>Correct a deficiency in the objdump disassembly output parsing<commit_after>/*
Copyright (c) 2016-2017 stoyan shopov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef DISASSEMBLY_HXX
#define DISASSEMBLY_HXX

#include <QFile>
#include <QVector>
#include <QPair>
#include <QRegExp>
#include <QDebug>
#include <QMessageBox>
#include <stdint.h>
#include "memory.hxx"
#include "target.hxx"
#include "util.hxx"

#include <platform.h>
#include <capstone/capstone.h>

enum
{
	DISASSEMBLY_AROUND_ADDRESS_CONTEXT_LINE_COUNT	= 100,
};

class Disassembly
{
private:
	csh cs_handle;
	Memory	memory;
	QByteArray	disassembly_text;
	QVector<QPair<uint32_t /* address */, int /* index in disassembly text */> > index_table;
	int indexOfAddress(uint32_t address)
	{
		int l = 0, h = index_table.size() - 1, m;
		while (l <= h)
		{
			m = (l + h) >> 1;
			if (index_table.at(m).first == address)
				break;
			if (index_table.at(m).first < address)
				l = m + 1;
			else
				h = m - 1;
		}
		if (l > h)
			return -1;
		return m;
	}
	QString disassembleBytes(const QByteArray & data, uint32_t address)
	{
		QString dis;
		int count;
		if (data.size() != 2 && data.size() != 4)
			Util::panic();
		cs_insn		* insn;

		if ((count = cs_disasm(cs_handle, (const uint8_t *) data.constData(), data.length(), address, 0, & insn) == 1) && insn->size == data.size())
			dis = QString("%1:\t%2\t%3\t\t%4")
		                                  .arg(insn->address, 8, 16, QChar('0'))
		                                  .arg(QString(QByteArray((const char *) insn->bytes, insn->size).toHex()))
		                                  .arg(insn->mnemonic).arg(insn->op_str);
		cs_free(insn, count);
		return dis;
	}
public:
	Disassembly(QByteArray disassembly, const Memory & memory)
	{
		int i = 0, x;
		bool ok;
		QRegExp rx("^\\s*(\\w+):"
		/* Note: a whitespace is expected here, because the objdump disassembly
		 * normally starts with something like:
		 * "<Filename>:	file format elf32-littlearm"
		 * and the file name may contain the complete path to the file.
		 * Now, on a windows machine, if the file is in a windows drive which is a
		 * valid hex digit (i.e., in the range 'a' - 'f'), then this line is being
		 * incorrectly detected as a valid disassembly line (e.g., if the file is in the 'c'
		 * drive, a disassmbly line is being detected for address 0x0000000c).
		 * To avoid such incorrect detection of disassembly lines in the objdump
		 * disassembly output, only accept lines which contain some whitespace after
		 * the colon character.
		 */
		"\\s+");
		this->memory = memory;
		if (cs_open(CS_ARCH_ARM, CS_MODE_THUMB, & cs_handle))
		{
			QMessageBox::critical(0, "failed to initialize the disassembly library",
					      "failed to initialize the disassembly library\n\n"
					      "this is a fatal error, and the troll will now abort");
			Util::panic();
		}
		//return;

		disassembly_text = disassembly;
		while (i < disassembly_text.size())
		{
			QString s(disassembly_text.mid(i, (x = disassembly_text.indexOf('\n', i)) - i));
			if (rx.indexIn(s) != -1)
			{
				uint32_t address = rx.cap(1).toUInt(& ok, 16);
				if (ok)
					index_table << QPair<uint32_t, int>(address, i);
			}
			if (x == -1)
				break;
			i = x + 1;
		}
		for (i = 1; i < index_table.size(); i ++)
			if (index_table.at(i).first <= index_table.at(i - 1).first)
				Util::panic();
	}
	/*! \todo	reading target memory here with	'readBytes()' is ***slow*** - maybe fix this */
	QList<QPair<uint32_t, QString> > disassemblyAroundAddress(uint32_t address, class Target * target, int * line_for_address = 0)
	{
		QString x;
		QList<QPair<uint32_t, QString> > dis;
		QPair<uint32_t, QString> t;
		uint32_t l, h, i = 0;
		QByteArray data;
		if (line_for_address)
			* line_for_address = -1;
		data = target->readBytes(address, 4, true);
		if (!data.size())
		{
			dis.push_back(QPair<uint32_t, QString> (address, QString("<<< cannot read memory at address $%1 >>>").arg(address, 8, 16, QChar('0'))));
			return dis;
		}
		if (!(x = disassembleBytes(data.left(2), address)).isEmpty())
			h = address + 2, dis.push_back(QPair<uint32_t, QString> (address, x));
		else if (!(x = disassembleBytes(data, address)).isEmpty())
			h = address + 4, dis.push_back(QPair<uint32_t, QString> (address, x));
		else
		{
			dis.push_back(QPair<uint32_t, QString> (address, QString("<<< cannot disassemble bytes at address $%1 >>>").arg(address, 8, 16, QChar('0'))));
			return dis;
		}
		l = address;
		for (i = 0; i < DISASSEMBLY_AROUND_ADDRESS_CONTEXT_LINE_COUNT; i ++)
		{
			l -= 4;
			data = target->readBytes(l, 4, true);
			if (!data.size())
			{
				dis.push_front(QPair<uint32_t, QString> (l, QString("<<< cannot read memory at address $%1 >>>").arg(l, 8, 16, QChar('0'))));
				return dis;
			}
			if (!(x = disassembleBytes(data.right(2), l + 2)).isEmpty())
				l += 2, t.first = l, t.second = x, dis.push_front(t);
			else if (!(x = disassembleBytes(data, l)).isEmpty())
				t.first = l, t.second = x, dis.push_front(t);
			else
				l += 2,t.first = l + 2, t.second = QString("<<< cannot disassemble bytes at address $%1 >>>").arg(l, 8, 16, QChar('0')),  dis.push_front(t);

			t.first = h;
			data = target->readBytes(h, 4, true);
			if (!data.size())
			{
				dis.push_back(QPair<uint32_t, QString> (h, QString("<<< cannot read memory at address $%1 >>>").arg(h, 8, 16, QChar('0'))));
				return dis;
			}
			if (!(x = disassembleBytes(data, h)).isEmpty())
				h += 4, t.second = x, dis.push_back(t);
			else if (!(x = disassembleBytes(data.left(2), h)).isEmpty())
				h += 2, t.second = x, dis.push_back(t);
			else
				h += 2, t.second = QString("<<< cannot disassemble bytes at address $%1 >>>").arg(h, 8, 16, QChar('0')), dis.push_back(t);
		}
		if (line_for_address)
			* line_for_address = i;
		return dis;
	}
	QList<QPair<uint32_t /* address */, QString /* disassembly */> > disassemblyForRange(uint32_t start, uint32_t end)
	{
		QList<QPair<uint32_t , QString > > dis;
		int i;
		while (start < end)
		{
			i = indexOfAddress(start);

			if (i == -1 || i == /* not really exact, but doesn't matter anyway */ index_table.size() - 1)
			{
				cs_insn		* insn;
				auto x = memory.data(start, 4);
				i = cs_disasm(cs_handle, (const uint8_t *) x.constData(), x.length(), start, 0, & insn);

				if (!i)
					return dis << QPair<uint32_t, QString>(start, QString("<<< no disassembly for address $%1 >>>").arg(start, 8, 16, QChar('0')));
				dis << QPair<uint32_t , QString >(insn->address, QString("%1:\t%2\t%3\t\t%4")
								  .arg(insn->address, 8, 16, QChar('0'))
								  .arg(QString(QByteArray((const char *) insn->bytes, insn->size).toHex()))
								  .arg(insn->mnemonic).arg(insn->op_str));
				start += insn->size;
				cs_free(insn, i);
			}
			else
			{
				dis << QPair<uint32_t , QString >(start, disassembly_text.mid(index_table.at(i).second, disassembly_text.indexOf('\n', index_table.at(i).second) - index_table.at(i).second ));
				start = index_table.at(++ i).first;
			}
		}
		return dis;
	}
	void disassemble(const uint8_t * bytes, int length, uint32_t address)
	{
		csh handle;
		cs_insn * insn;
		int i;
		size_t count;
		cs_err err;

			err = cs_open(CS_ARCH_ARM, CS_MODE_THUMB, &handle);
			if (err)
			{
				printf("Failed on cs_open() with error returned: %u\n", err);
				return;
			}

			count = cs_disasm(handle, bytes, length, address, 0, & insn);
			if (count)
			{
				size_t j;

				//print_string_hex(platforms[i].code, platforms[i].size);
				printf("Disasm:\n");

				for (j = 0; j < count; j++) {
					fprintf(stderr, "%08x"  ":\t%s\t\t%s\n",
					       (uint32_t) insn[j].address, insn[j].mnemonic, insn[j].op_str);
				}

				// print out the next offset, after the last insn
				printf("0x%08x"  ":\n", (uint32_t) insn[j-1].address + insn[j-1].size);

				// free memory allocated by cs_disasm()
				cs_free(insn, count);
			}

			printf("\n");

			cs_close(&handle);
	}
};

#endif // DISASSEMBLY_HXX
<|endoftext|>


<commit_before>#ifndef V_SMC_HELPER_PARALLEL_TBB_HPP
#define V_SMC_HELPER_PARALLEL_TBB_HPP

#include <tbb/tbb.h>
#include <vSMC/internal/common.hpp>

namespace vSMC {

/// \brief Sampler::init_type class for helping implementing SMC using TBB
///
/// \note The template parameter has to be type StateBase or its derived class.
/// \sa vSMC::InitializeSeq
template <typename T>
class InitializeTBB : public InitializeSeq<T>
{
    public :

    typedef typename InitializeSeq<T>::initialize_state_type
        initialize_state_type;
    typedef typename InitializeSeq<T>::initialize_param_type
        initialize_param_type;
    typedef typename InitializeSeq<T>::pre_processor_type
        pre_processor_type;
    typedef typename InitializeSeq<T>::post_processor_type
        post_processor_type;

    explicit InitializeTBB (
            initialize_state_type initialize_state = NULL,
            initialize_param_type initialize_param = NULL,
            pre_processor_type    pre_processor    = NULL,
            post_processor_type   post_processor   = NULL) :
        InitializeSeq<T>(initialize_state, initialize_param,
                pre_processor, post_processor) {}

    InitializeTBB (const InitializeTBB<T> &init) {}

    InitializeTBB<T> & operator= (const InitializeTBB<T> &init) {return *this;}

    /// \brief Operator called by Sampler for initialize the particle set
    ///
    /// \param particle The Particle set passed by Sampler
    /// \param param Additional parameters
    ///
    /// \return Accept count
    std::size_t operator() (Particle<T> &particle, void *param)
    {
        this->initialize_param(particle, param);
        this->pre_processor(particle);
        log_weight_.resize(particle.size());
        accept_.resize(particle.size());
        tbb::parallel_for(tbb::blocked_range<std::size_t>(0, particle.size()),
                Worker_(this, &particle, log_weight_.data(), accept_.data()));

        particle.set_log_weight(log_weight_.data());
        this->post_processor(particle);

        return accept_.sum();
    }

    private :

    Eigen::VectorXd log_weight_;
    Eigen::VectorXi accept_;

    class Worker_
    {
        public :

        Worker_ (InitializeTBB<T> *init,
                Particle<T> *particle, double *log_weight, int *accept) :
            init_(init), particle_(particle),
            log_weight_(log_weight), accept_(accept) {}

        void operator () (const tbb::blocked_range<std::size_t> &range) const
        {
            for (std::size_t i = range.begin(); i != range.end(); ++i) {
                accept_[i] = init_->initialize_state(SingleParticle<T>(
                            i, log_weight_ + i, particle_));
            }
        }

        private :

        InitializeTBB<T> *const init_;
        Particle<T> *const particle_;
        double *const log_weight_;
        int *const accept_;
    }; // class Woker_
}; // class InitializeTBB

/// \brief Sampler::move_type class for helping implementing SMC using TBB
///
/// \note The template parameter has to be type StateBase or its derived class.
/// \sa vSMC::MoveSeq
template <typename T>
class MoveTBB : public MoveSeq<T>
{
    public :

    typedef typename MoveSeq<T>::move_state_type     move_state_type;
    typedef typename MoveSeq<T>::weight_action_type  weight_action_type;
    typedef typename MoveSeq<T>::pre_processor_type  pre_processor_type;
    typedef typename MoveSeq<T>::post_processor_type post_processor_type;

    explicit MoveTBB (
            move_state_type     move_state     = NULL,
            weight_action_type  weight_action  = NULL,
            pre_processor_type  pre_processor  = NULL,
            post_processor_type post_processor = NULL) :
        MoveSeq<T>(move_state, weight_action, pre_processor, post_processor) {}

    MoveTBB (const MoveTBB<T> &move) {}

    MoveTBB<T> & operator= (const MoveTBB<T> &move) {return *this;}

    /// \brief Operator called by Sampler for move the particle set
    ///
    /// \param iter The iteration number
    /// \param particle The Particle set passed by Sampler
    ///
    /// \return Accept count
    std::size_t operator () (std::size_t iter, Particle<T> &particle)
    {
        this->pre_processor(iter, particle);
        weight_.resize(particle.size());
        accept_.resize(particle.size());
        tbb::parallel_for(tbb::blocked_range<std::size_t>(0, particle.size()),
                Worker_(this, iter, &particle, weight_.data(),
                    accept_.data()));
        MoveSeq<T>::set_weight(this->weight_action(), particle,
                weight_.data());
        this->post_processor(iter, particle);

        return accept_.sum();
    }

    private :

    Eigen::VectorXd weight_;
    Eigen::VectorXi accept_;

    class Worker_
    {
        public :

        Worker_ (MoveTBB<T> *move, std::size_t iter,
                Particle<T> *particle, double *weight, int *accept) :
            move_(move), iter_(iter), particle_(particle),
            weight_(weight), accept_(accept) {}

        void operator () (const tbb::blocked_range<std::size_t> &range) const
        {
            for (std::size_t i = range.begin(); i != range.end(); ++i) {
                accept_[i] = move_->move_state(iter_, SingleParticle<T>(
                            i, weight_ + i, particle_));
            }
        }

        private :

        MoveTBB<T> *const move_;
        const std::size_t iter_;
        Particle<T> *const particle_;
        double *const weight_;
        int *const accept_;
    }; // class Woker_
}; // class MoveTBB

/// \brief Monitor::integral_type class for helping implementing SMC using TBB
///
/// \note The template parameter has to be type StateBase or its derived class.
/// \sa vSMC::MonitorSeq
template <typename T, unsigned Dim>
class MonitorTBB : public MonitorSeq<T, Dim>
{
    public :

    typedef typename MonitorSeq<T>::monitor_state_type monitor_state_type;

    explicit MonitorTBB (monitor_state_type monitor = NULL) :
        MonitorSeq<T, Dim>(monitor) {}

    /// \brief Operator called by Monitor to record Monte Carlo integration
    ///
    /// \param iter The iteration number
    /// \param particle The Particle set passed by Sampler
    /// \param [out] res The integrands. Sum(res * weight) is the Monte Carlo
    /// integration result.
    void operator () (std::size_t iter, Particle<T> &particle, double *res)
    {
        tbb::parallel_for(tbb::blocked_range<std::size_t>(0, particle.size()),
                Worker_(this, iter, &particle, res));
    }

    private :

    class Worker_
    {
        public :

        Worker_ (MonitorTBB<T, Dim> *monitor, std::size_t iter,
                Particle<T> *particle, double *res) :
            monitor_(monitor), iter_(iter), particle_(particle), res_(res) {}

        void operator () (const tbb::blocked_range<std::size_t> &range) const
        {
            for (std::size_t i = range.begin(); i != range.end(); ++i) {
                monitor_->monitor_state(iter_, SingleParticle<T>(
                            i, NULL, particle_), res_ + i * Dim);
            }
        }

        private :

        MonitorTBB<T, Dim> *const monitor_;
        const std::size_t iter_;
        Particle<T> *const particle_;
        double *const res_;
    }; // class Worker_
}; // class MonitorTBB

/// \brief Path::integral_type class for helping implementing SMC using TBB
///
/// \note The template parameter has to be type StateBase or its derived class.
/// \sa vSMC::PathSeq
template <typename T>
class PathTBB : public PathSeq<T>
{
    public :

    typedef typename PathSeq<T>::path_state_type path_state_type;
    typedef typename PathSeq<T>::width_state_type width_state_type;

    explicit PathTBB (
            path_state_type path = NULL, width_state_type width = NULL) :
        PathSeq<T>(path, width) {}

    /// \brief Operator called by Path to record path sampling integrands and
    /// widths
    ///
    /// \param iter The iteration number
    /// \param particle The particle set passed by Sampler
    /// \param [out] res The integrands. Sum(res * weight) is the path
    ///
    /// \return The width
    /// sampling integrand.
    double operator () (std::size_t iter, Particle<T> &particle, double *res)
    {
        tbb::parallel_for(tbb::blocked_range<std::size_t>(0, particle.size()),
                Worker_(this, iter, &particle, res));

        return this->width_state(iter, particle);
    }

    private :

    class Worker_
    {
        public :

        Worker_ (PathTBB<T> *path, std::size_t iter, Particle<T> *particle,
                double *res) :
            path_(path), iter_(iter), particle_(particle), res_(res) {}

        void operator () (const tbb::blocked_range<std::size_t> &range) const
        {
            for (std::size_t i = range.begin(); i != range.end(); ++i) {
                res_[i] = path_->path_state(iter_, SingleParticle<T>(
                            i, NULL, particle_));
            }
        }

        private :

        PathTBB<T> *const path_;
        const std::size_t iter_;
        Particle<T> *const particle_;
        double *const res_;
    }; // class Worker_
}; // PathTBB

} // namespace vSMC

#endif // V_SMC_HELPER_PARALLEL_TBB_HPP
<commit_msg>avoid stdint.h error as best<commit_after>#ifndef V_SMC_HELPER_PARALLEL_TBB_HPP
#define V_SMC_HELPER_PARALLEL_TBB_HPP

#include <vSMC/internal/common.hpp>
#include <tbb/tbb.h>

namespace vSMC {

/// \brief Sampler::init_type class for helping implementing SMC using TBB
///
/// \note The template parameter has to be type StateBase or its derived class.
/// \sa vSMC::InitializeSeq
template <typename T>
class InitializeTBB : public InitializeSeq<T>
{
    public :

    typedef typename InitializeSeq<T>::initialize_state_type
        initialize_state_type;
    typedef typename InitializeSeq<T>::initialize_param_type
        initialize_param_type;
    typedef typename InitializeSeq<T>::pre_processor_type
        pre_processor_type;
    typedef typename InitializeSeq<T>::post_processor_type
        post_processor_type;

    explicit InitializeTBB (
            initialize_state_type initialize_state = NULL,
            initialize_param_type initialize_param = NULL,
            pre_processor_type    pre_processor    = NULL,
            post_processor_type   post_processor   = NULL) :
        InitializeSeq<T>(initialize_state, initialize_param,
                pre_processor, post_processor) {}

    InitializeTBB (const InitializeTBB<T> &init) {}

    InitializeTBB<T> & operator= (const InitializeTBB<T> &init) {return *this;}

    /// \brief Operator called by Sampler for initialize the particle set
    ///
    /// \param particle The Particle set passed by Sampler
    /// \param param Additional parameters
    ///
    /// \return Accept count
    std::size_t operator() (Particle<T> &particle, void *param)
    {
        this->initialize_param(particle, param);
        this->pre_processor(particle);
        log_weight_.resize(particle.size());
        accept_.resize(particle.size());
        tbb::parallel_for(tbb::blocked_range<std::size_t>(0, particle.size()),
                Worker_(this, &particle, log_weight_.data(), accept_.data()));

        particle.set_log_weight(log_weight_.data());
        this->post_processor(particle);

        return accept_.sum();
    }

    private :

    Eigen::VectorXd log_weight_;
    Eigen::VectorXi accept_;

    class Worker_
    {
        public :

        Worker_ (InitializeTBB<T> *init,
                Particle<T> *particle, double *log_weight, int *accept) :
            init_(init), particle_(particle),
            log_weight_(log_weight), accept_(accept) {}

        void operator () (const tbb::blocked_range<std::size_t> &range) const
        {
            for (std::size_t i = range.begin(); i != range.end(); ++i) {
                accept_[i] = init_->initialize_state(SingleParticle<T>(
                            i, log_weight_ + i, particle_));
            }
        }

        private :

        InitializeTBB<T> *const init_;
        Particle<T> *const particle_;
        double *const log_weight_;
        int *const accept_;
    }; // class Woker_
}; // class InitializeTBB

/// \brief Sampler::move_type class for helping implementing SMC using TBB
///
/// \note The template parameter has to be type StateBase or its derived class.
/// \sa vSMC::MoveSeq
template <typename T>
class MoveTBB : public MoveSeq<T>
{
    public :

    typedef typename MoveSeq<T>::move_state_type     move_state_type;
    typedef typename MoveSeq<T>::weight_action_type  weight_action_type;
    typedef typename MoveSeq<T>::pre_processor_type  pre_processor_type;
    typedef typename MoveSeq<T>::post_processor_type post_processor_type;

    explicit MoveTBB (
            move_state_type     move_state     = NULL,
            weight_action_type  weight_action  = NULL,
            pre_processor_type  pre_processor  = NULL,
            post_processor_type post_processor = NULL) :
        MoveSeq<T>(move_state, weight_action, pre_processor, post_processor) {}

    MoveTBB (const MoveTBB<T> &move) {}

    MoveTBB<T> & operator= (const MoveTBB<T> &move) {return *this;}

    /// \brief Operator called by Sampler for move the particle set
    ///
    /// \param iter The iteration number
    /// \param particle The Particle set passed by Sampler
    ///
    /// \return Accept count
    std::size_t operator () (std::size_t iter, Particle<T> &particle)
    {
        this->pre_processor(iter, particle);
        weight_.resize(particle.size());
        accept_.resize(particle.size());
        tbb::parallel_for(tbb::blocked_range<std::size_t>(0, particle.size()),
                Worker_(this, iter, &particle, weight_.data(),
                    accept_.data()));
        MoveSeq<T>::set_weight(this->weight_action(), particle,
                weight_.data());
        this->post_processor(iter, particle);

        return accept_.sum();
    }

    private :

    Eigen::VectorXd weight_;
    Eigen::VectorXi accept_;

    class Worker_
    {
        public :

        Worker_ (MoveTBB<T> *move, std::size_t iter,
                Particle<T> *particle, double *weight, int *accept) :
            move_(move), iter_(iter), particle_(particle),
            weight_(weight), accept_(accept) {}

        void operator () (const tbb::blocked_range<std::size_t> &range) const
        {
            for (std::size_t i = range.begin(); i != range.end(); ++i) {
                accept_[i] = move_->move_state(iter_, SingleParticle<T>(
                            i, weight_ + i, particle_));
            }
        }

        private :

        MoveTBB<T> *const move_;
        const std::size_t iter_;
        Particle<T> *const particle_;
        double *const weight_;
        int *const accept_;
    }; // class Woker_
}; // class MoveTBB

/// \brief Monitor::integral_type class for helping implementing SMC using TBB
///
/// \note The template parameter has to be type StateBase or its derived class.
/// \sa vSMC::MonitorSeq
template <typename T, unsigned Dim>
class MonitorTBB : public MonitorSeq<T, Dim>
{
    public :

    typedef typename MonitorSeq<T>::monitor_state_type monitor_state_type;

    explicit MonitorTBB (monitor_state_type monitor = NULL) :
        MonitorSeq<T, Dim>(monitor) {}

    /// \brief Operator called by Monitor to record Monte Carlo integration
    ///
    /// \param iter The iteration number
    /// \param particle The Particle set passed by Sampler
    /// \param [out] res The integrands. Sum(res * weight) is the Monte Carlo
    /// integration result.
    void operator () (std::size_t iter, Particle<T> &particle, double *res)
    {
        tbb::parallel_for(tbb::blocked_range<std::size_t>(0, particle.size()),
                Worker_(this, iter, &particle, res));
    }

    private :

    class Worker_
    {
        public :

        Worker_ (MonitorTBB<T, Dim> *monitor, std::size_t iter,
                Particle<T> *particle, double *res) :
            monitor_(monitor), iter_(iter), particle_(particle), res_(res) {}

        void operator () (const tbb::blocked_range<std::size_t> &range) const
        {
            for (std::size_t i = range.begin(); i != range.end(); ++i) {
                monitor_->monitor_state(iter_, SingleParticle<T>(
                            i, NULL, particle_), res_ + i * Dim);
            }
        }

        private :

        MonitorTBB<T, Dim> *const monitor_;
        const std::size_t iter_;
        Particle<T> *const particle_;
        double *const res_;
    }; // class Worker_
}; // class MonitorTBB

/// \brief Path::integral_type class for helping implementing SMC using TBB
///
/// \note The template parameter has to be type StateBase or its derived class.
/// \sa vSMC::PathSeq
template <typename T>
class PathTBB : public PathSeq<T>
{
    public :

    typedef typename PathSeq<T>::path_state_type path_state_type;
    typedef typename PathSeq<T>::width_state_type width_state_type;

    explicit PathTBB (
            path_state_type path = NULL, width_state_type width = NULL) :
        PathSeq<T>(path, width) {}

    /// \brief Operator called by Path to record path sampling integrands and
    /// widths
    ///
    /// \param iter The iteration number
    /// \param particle The particle set passed by Sampler
    /// \param [out] res The integrands. Sum(res * weight) is the path
    ///
    /// \return The width
    /// sampling integrand.
    double operator () (std::size_t iter, Particle<T> &particle, double *res)
    {
        tbb::parallel_for(tbb::blocked_range<std::size_t>(0, particle.size()),
                Worker_(this, iter, &particle, res));

        return this->width_state(iter, particle);
    }

    private :

    class Worker_
    {
        public :

        Worker_ (PathTBB<T> *path, std::size_t iter, Particle<T> *particle,
                double *res) :
            path_(path), iter_(iter), particle_(particle), res_(res) {}

        void operator () (const tbb::blocked_range<std::size_t> &range) const
        {
            for (std::size_t i = range.begin(); i != range.end(); ++i) {
                res_[i] = path_->path_state(iter_, SingleParticle<T>(
                            i, NULL, particle_));
            }
        }

        private :

        PathTBB<T> *const path_;
        const std::size_t iter_;
        Particle<T> *const particle_;
        double *const res_;
    }; // class Worker_
}; // PathTBB

} // namespace vSMC

#endif // V_SMC_HELPER_PARALLEL_TBB_HPP
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2020 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#ifndef VCF2MULTIALIGN_COMBINE_MSA_VARIANT_WRITER_HH
#define VCF2MULTIALIGN_COMBINE_MSA_VARIANT_WRITER_HH

#include <libbio/assert.hh>
#include <string>
#include <vector>
#include "types.hh"

namespace vcf2multialign {

	enum class variant_origin : std::uint8_t
	{
		MSA,
		VC
	};

	struct variant_description
	{
		// The genotype is stored in a std::vector <bool> here.
		// A pair of integers could be used instead, though, since
		// at the moment we only handle unphased VCF files and thus
		// the order of the values does not matter.

		std::string			ref;
		std::string			alt;
		std::vector <bool>	genotype;
		std::size_t			position{};
		std::int32_t		overlap_count{};
		variant_origin		origin{};
		bool				is_skipped{};

		variant_description() = default;

		variant_description(std::size_t const ploidy, std::int32_t const gt_count, variant_origin const origin_):
			genotype(ploidy, true),
			origin(origin_)
		{
			libbio_assert_lte(gt_count, ploidy);
			// Assign the GT values.
			genotype.resize(gt_count);
			genotype.resize(ploidy, false);
		}

		template <typename t_string_1, typename t_string_2>
		variant_description(
			std::size_t const position_,
			t_string_1 &&ref_,
			t_string_2 &&alt_,
			std::size_t const ploidy,
			std::int32_t const overlap_count_,
			variant_origin const origin_
		):
			ref(std::forward <t_string_1>(ref_)),
			alt(std::forward <t_string_2>(alt_)),
			genotype(ploidy, false),
			position(position_),
			overlap_count(overlap_count_),
			origin(origin_)
		{
			libbio_assert_lte(overlap_count, ploidy);
			// Assign the GT values.
			genotype.resize(overlap_count);
			genotype.resize(ploidy, true);
		}
	};

	class variant_writer
	{
	protected:
		std::vector <variant_description>	m_output_variants;
		std::string							m_output_chr_id;
		std::ostream						*m_os{};

	public:
		variant_writer() = default;
		variant_writer(std::ostream &os, std::string &&output_chr_id):
			m_output_chr_id(std::move(output_chr_id)),
			m_os(&os)
		{
		}

		std::size_t size() const { return m_output_variants.size(); }
		variant_description &emplace_back(variant_description &&desc) { return m_output_variants.emplace_back(std::move(desc)); }

		void output_vcf_header() const;
		void merge_output_variants(std::size_t const partition_point);
		void filter_processed_variants_and_output(std::size_t const min_unhandled_ref_pos);
	};
}

#endif
<commit_msg>Add check for overlap count gt. ploidy<commit_after>/*
 * Copyright (c) 2020 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#ifndef VCF2MULTIALIGN_COMBINE_MSA_VARIANT_WRITER_HH
#define VCF2MULTIALIGN_COMBINE_MSA_VARIANT_WRITER_HH

#include <libbio/assert.hh>
#include <string>
#include <vector>
#include "types.hh"

namespace vcf2multialign {

	enum class variant_origin : std::uint8_t
	{
		MSA,
		VC
	};

	struct variant_description
	{
	protected:
		struct private_tag {};

	public:
		// The genotype is stored in a std::vector <bool> here.
		// A pair of integers could be used instead, though, since
		// at the moment we only handle unphased VCF files and thus
		// the order of the values does not matter.

		std::string			ref;
		std::string			alt;
		std::vector <bool>	genotype;
		std::size_t			position{};
		std::int32_t		overlap_count{};
		variant_origin		origin{};
		bool				is_skipped{};

	protected:
		template <typename t_string_1, typename t_string_2>
		variant_description(
			std::size_t const position_,
			t_string_1 &&ref_,
			t_string_2 &&alt_,
			std::size_t const ploidy,
			std::int32_t const overlap_count_,
			variant_origin const origin_,
			private_tag const
		):
			ref(std::forward <t_string_1>(ref_)),
			alt(std::forward <t_string_2>(alt_)),
			genotype(ploidy, false),
			position(position_),
			overlap_count(overlap_count_),
			origin(origin_)
		{
			libbio_assert_lte(overlap_count, ploidy);
			// Assign the GT values.
			genotype.resize(overlap_count);
			genotype.resize(ploidy, true);
		}

	public:
		variant_description() = default;

		variant_description(std::size_t const ploidy, std::int32_t const gt_count, variant_origin const origin_):
			genotype(ploidy, true),
			origin(origin_)
		{
			libbio_assert_lte(gt_count, ploidy);
			// Assign the GT values.
			genotype.resize(gt_count);
			genotype.resize(ploidy, false);
		}

		template <typename t_string_1, typename t_string_2>
		variant_description(
			std::size_t const position_,
			t_string_1 &&ref_,
			t_string_2 &&alt_,
			std::size_t const ploidy,
			std::int32_t const overlap_count_,
			variant_origin const origin_
		):
			variant_description(
				position_,
				std::forward <t_string_1>(ref_),
				std::forward <t_string_2>(alt_),
				ploidy,
				(overlap_count_ < 0 ? overlap_count_ : std::min <std::int32_t>(overlap_count_, ploidy)),
				origin_,
				private_tag()
			)
		{
		}
	};

	class variant_writer
	{
	protected:
		std::vector <variant_description>	m_output_variants;
		std::string							m_output_chr_id;
		std::ostream						*m_os{};

	public:
		variant_writer() = default;
		variant_writer(std::ostream &os, std::string &&output_chr_id):
			m_output_chr_id(std::move(output_chr_id)),
			m_os(&os)
		{
		}

		std::size_t size() const { return m_output_variants.size(); }
		variant_description &emplace_back(variant_description &&desc) { return m_output_variants.emplace_back(std::move(desc)); }

		void output_vcf_header() const;
		void merge_output_variants(std::size_t const partition_point);
		void filter_processed_variants_and_output(std::size_t const min_unhandled_ref_pos);
	};
}

#endif
<|endoftext|>


<commit_before>// flagStay.cpp : Defines the entry point for the DLL application.
//

#include "bzfsAPI.h"
#include <string>
#include <vector>
#include <math.h>

BZ_GET_PLUGIN_VERSION

class FlagStayZoneHandler : public bz_CustomMapObjectHandler
{
public:
	virtual bool handle ( bzApiString object, bz_CustomMapObjectInfo *data );
};

FlagStayZoneHandler	flagStayZoneHandler;

class EventHandler : public bz_EventHandler
{
public:
	virtual void process ( bz_EventData *eventData );
};

EventHandler eventHandler;

BZF_PLUGIN_CALL int bz_Load ( const char* /*commandLine*/ )
{
  bz_debugMessage(4,"flagStay plugin loaded");
  bz_registerCustomMapObject("FLAGSTAYZONE",&flagStayZoneHandler);

  bz_registerEvent(bz_ePlayerUpdateEvent,&eventHandler);
  return 0;
}

BZF_PLUGIN_CALL int bz_Unload ( void )
{
  bz_removeEvent(bz_ePlayerUpdateEvent,&eventHandler);
  bz_removeCustomMapObject("FLAGSTAYZONE");
  bz_debugMessage(4,"flagStay plugin unloaded");
  return 0;
}

class FlagStayZone
{
public:
	FlagStayZone()
	{
		box = false;
		xMax = xMin = yMax = yMin = zMax = zMin = rad = 0;
	}

	bool box;
	float xMax,xMin,yMax,yMin,zMax,zMin;
	float rad;

	std::string message;
	bool pointIn ( float pos[3] )
	{
		if ( box )
		{
			if ( pos[0] > xMax || pos[0] < xMin )
				return false;

			if ( pos[1] > yMax || pos[1] < yMin )
				return false;

			if ( pos[2] > zMax || pos[2] < zMin )
				return false;
		}
		else
		{
			float vec[3];
			vec[0] = pos[0]-xMax;
			vec[1] = pos[1]-yMax;
			vec[2] = pos[2]-zMax;

			float dist = sqrt(vec[0]*vec[0]+vec[1]*vec[1]);
			if ( dist > rad)
				return false;

			if ( pos[2] > zMax || pos[2] < zMin )
				return false;

		}
		return true;
	}

	bool checkFlag ( const char* flag )
	{
		for ( unsigned int i = 0; i < flagList.size(); i++ )
		{
			if ( flagList[i] == flag )
				return true;
		}
		return false;
	}

	std::vector<std::string> flagList;
};

std::vector <FlagStayZone> zoneList;

bool FlagStayZoneHandler::handle ( bzApiString object, bz_CustomMapObjectInfo *data )
{
	if (object != "FLAGSTAYZONE" || !data)
		return false;

	FlagStayZone newZone;

	// parse all the chunks
	for ( unsigned int i = 0; i < data->data.size(); i++ )
	{
		std::string line = data->data.get(i).c_str();

		bzAPIStringList *nubs = bz_newStringList();
		nubs->tokenize(line.c_str()," ",0,true);

		if ( nubs->size() > 0)
		{
			std::string key = bz_toupper(nubs->get(0).c_str());

			if ( key == "BBOX" && nubs->size() > 6)
			{
				newZone.box = true;
				newZone.xMin = (float)atof(nubs->get(1).c_str());
				newZone.xMax = (float)atof(nubs->get(2).c_str());
				newZone.yMin = (float)atof(nubs->get(3).c_str());
				newZone.yMax = (float)atof(nubs->get(4).c_str());
				newZone.zMin = (float)atof(nubs->get(5).c_str());
				newZone.zMax = (float)atof(nubs->get(6).c_str());
			}
			else if ( key == "CYLINDER" && nubs->size() > 5)
			{
				newZone.box = false;
				newZone.rad = (float)atof(nubs->get(5).c_str());
				newZone.xMax =(float)atof(nubs->get(1).c_str());
				newZone.yMax =(float)atof(nubs->get(2).c_str());
				newZone.zMin =(float)atof(nubs->get(3).c_str());
				newZone.zMax =(float)atof(nubs->get(4).c_str());
			}
			else if ( key == "FLAG" && nubs->size() > 1)
			{
				std::string flag = nubs->get(1).c_str();
				newZone.flagList.push_back(flag);
			}
			else if ( key == "MESSAGE" && nubs->size() > 1 )
			{
				newZone.message = nubs->get(1).c_str();
			}
		}
		bz_deleteStringList(nubs);
	}
	zoneList.push_back(newZone);
	return true;
}

void EventHandler::process ( bz_EventData *eventData )
{
	float pos[3] = {0};

	int playerID = -1;

	switch (eventData->eventType)
	{
	case bz_ePlayerUpdateEvent:
		pos[0] = ((bz_PlayerUpdateEventData*)eventData)->pos[0];
		pos[1] = ((bz_PlayerUpdateEventData*)eventData)->pos[1];
		pos[2] = ((bz_PlayerUpdateEventData*)eventData)->pos[2];
		playerID = ((bz_PlayerUpdateEventData*)eventData)->playerID;
		break;

	case bz_eShotFiredEvent:
		pos[0] = ((bz_ShotFiredEventData*)eventData)->pos[0];
		pos[1] = ((bz_ShotFiredEventData*)eventData)->pos[1];
		pos[2] = ((bz_ShotFiredEventData*)eventData)->pos[2];
		playerID = ((bz_ShotFiredEventData*)eventData)->playerID;
		break;
	}

	const char* flagAbrev = bz_getPlayerFlag(playerID);
	if (!flagAbrev)
		return;

	// check and see if a zone cares about the current flag
	for ( unsigned int i = 0; i < zoneList.size(); i++ )
	{
		if ( zoneList[i].checkFlag(flagAbrev) )
		{
			if ( !zoneList[i].pointIn(pos) )	// they have taken the flag out of a zone, pop it.
			{
				bz_removePlayerFlag(playerID);
				if (zoneList[i].message.size())
					bz_sendTextMessage(BZ_SERVER,playerID,zoneList[i].message.c_str());
				i = (unsigned int)zoneList.size();	// finish out
			}
		}
	}
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<commit_msg>support multiple zones correctly<commit_after>// flagStay.cpp : Defines the entry point for the DLL application.
//

#include "bzfsAPI.h"
#include <string>
#include <vector>
#include <math.h>

BZ_GET_PLUGIN_VERSION

class FlagStayZoneHandler : public bz_CustomMapObjectHandler
{
public:
	virtual bool handle ( bzApiString object, bz_CustomMapObjectInfo *data );
};

FlagStayZoneHandler	flagStayZoneHandler;

class EventHandler : public bz_EventHandler
{
public:
	virtual void process ( bz_EventData *eventData );
};

EventHandler eventHandler;

BZF_PLUGIN_CALL int bz_Load ( const char* /*commandLine*/ )
{
  bz_debugMessage(4,"flagStay plugin loaded");
  bz_registerCustomMapObject("FLAGSTAYZONE",&flagStayZoneHandler);

  bz_registerEvent(bz_ePlayerUpdateEvent,&eventHandler);
  return 0;
}

BZF_PLUGIN_CALL int bz_Unload ( void )
{
  bz_removeEvent(bz_ePlayerUpdateEvent,&eventHandler);
  bz_removeCustomMapObject("FLAGSTAYZONE");
  bz_debugMessage(4,"flagStay plugin unloaded");
  return 0;
}

class FlagStayZone
{
public:
	FlagStayZone()
	{
		box = false;
		xMax = xMin = yMax = yMin = zMax = zMin = rad = 0;
	}

	bool box;
	float xMax,xMin,yMax,yMin,zMax,zMin;
	float rad;

	std::string message;
	bool pointIn ( float pos[3] )
	{
		if ( box )
		{
			if ( pos[0] > xMax || pos[0] < xMin )
				return false;

			if ( pos[1] > yMax || pos[1] < yMin )
				return false;

			if ( pos[2] > zMax || pos[2] < zMin )
				return false;
		}
		else
		{
			float vec[3];
			vec[0] = pos[0]-xMax;
			vec[1] = pos[1]-yMax;
			vec[2] = pos[2]-zMax;

			float dist = sqrt(vec[0]*vec[0]+vec[1]*vec[1]);
			if ( dist > rad)
				return false;

			if ( pos[2] > zMax || pos[2] < zMin )
				return false;

		}
		return true;
	}

	bool checkFlag ( const char* flag )
	{
		for ( unsigned int i = 0; i < flagList.size(); i++ )
		{
			if ( flagList[i] == flag )
				return true;
		}
		return false;
	}

	std::vector<std::string> flagList;
};

std::vector <FlagStayZone> zoneList;

bool FlagStayZoneHandler::handle ( bzApiString object, bz_CustomMapObjectInfo *data )
{
	if (object != "FLAGSTAYZONE" || !data)
		return false;

	FlagStayZone newZone;

	// parse all the chunks
	for ( unsigned int i = 0; i < data->data.size(); i++ )
	{
		std::string line = data->data.get(i).c_str();

		bzAPIStringList *nubs = bz_newStringList();
		nubs->tokenize(line.c_str()," ",0,true);

		if ( nubs->size() > 0)
		{
			std::string key = bz_toupper(nubs->get(0).c_str());

			if ( key == "BBOX" && nubs->size() > 6)
			{
				newZone.box = true;
				newZone.xMin = (float)atof(nubs->get(1).c_str());
				newZone.xMax = (float)atof(nubs->get(2).c_str());
				newZone.yMin = (float)atof(nubs->get(3).c_str());
				newZone.yMax = (float)atof(nubs->get(4).c_str());
				newZone.zMin = (float)atof(nubs->get(5).c_str());
				newZone.zMax = (float)atof(nubs->get(6).c_str());
			}
			else if ( key == "CYLINDER" && nubs->size() > 5)
			{
				newZone.box = false;
				newZone.rad = (float)atof(nubs->get(5).c_str());
				newZone.xMax =(float)atof(nubs->get(1).c_str());
				newZone.yMax =(float)atof(nubs->get(2).c_str());
				newZone.zMin =(float)atof(nubs->get(3).c_str());
				newZone.zMax =(float)atof(nubs->get(4).c_str());
			}
			else if ( key == "FLAG" && nubs->size() > 1)
			{
				std::string flag = nubs->get(1).c_str();
				newZone.flagList.push_back(flag);
			}
			else if ( key == "MESSAGE" && nubs->size() > 1 )
			{
				newZone.message = nubs->get(1).c_str();
			}
		}
		bz_deleteStringList(nubs);
	}
	zoneList.push_back(newZone);
	return true;
}

void EventHandler::process ( bz_EventData *eventData )
{
	float pos[3] = {0};

	int playerID = -1;

	switch (eventData->eventType)
	{
	case bz_ePlayerUpdateEvent:
		pos[0] = ((bz_PlayerUpdateEventData*)eventData)->pos[0];
		pos[1] = ((bz_PlayerUpdateEventData*)eventData)->pos[1];
		pos[2] = ((bz_PlayerUpdateEventData*)eventData)->pos[2];
		playerID = ((bz_PlayerUpdateEventData*)eventData)->playerID;
		break;

	case bz_eShotFiredEvent:
		pos[0] = ((bz_ShotFiredEventData*)eventData)->pos[0];
		pos[1] = ((bz_ShotFiredEventData*)eventData)->pos[1];
		pos[2] = ((bz_ShotFiredEventData*)eventData)->pos[2];
		playerID = ((bz_ShotFiredEventData*)eventData)->playerID;
		break;
	}

	const char* flagAbrev = bz_getPlayerFlag(playerID);
	if (!flagAbrev)
		return;

	std::vector<FlagStayZone*> validZones;

	// check and see if a zone cares about the current flag
	for ( unsigned int i = 0; i < zoneList.size(); i++ )
	{
		if ( zoneList[i].checkFlag(flagAbrev) )
			validZones.push_back(&zoneList[i]);
	}

	bool insideOne = false;
	for ( unsigned int i = 0; i < validZones.size(); i++ )
	{
		if ( validZones[i]->pointIn(pos) )	// they have taken the flag out of a zone, pop it.
			insideOne = true;
	}

	if (!insideOne)
	{
		bz_removePlayerFlag(playerID);
		if (zoneList[i].message.size())
			bz_sendTextMessage(BZ_SERVER,playerID,zoneList[i].message.c_str());
	}
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<|endoftext|>


<commit_before>// flagStay.cpp : Defines the entry point for the DLL application.
//

#include "bzfsAPI.h"
#include <string>
#include <vector>
#include <math.h>

BZ_GET_PLUGIN_VERSION

class FlagStayZoneHandler : public bz_CustomMapObjectHandler
{
public:
	virtual bool handle ( bzApiString object, bz_CustomMapObjectInfo *data );
};

FlagStayZoneHandler	flagStayZoneHandler;

class EventHandler : public bz_EventHandler
{
public:
	virtual void process ( bz_EventData *eventData );
};

EventHandler eventHandler;

BZF_PLUGIN_CALL int bz_Load ( const char* /*commandLine*/ )
{
  bz_debugMessage(4,"flagStay plugin loaded");
  bz_registerCustomMapObject("FLAGSTAYZONE",&flagStayZoneHandler);

  bz_registerEvent(bz_ePlayerUpdateEvent,&eventHandler);
  return 0;
}

BZF_PLUGIN_CALL int bz_Unload ( void )
{
  bz_removeEvent(bz_ePlayerUpdateEvent,&eventHandler);
  bz_removeCustomMapObject("FLAGSTAYZONE");
  bz_debugMessage(4,"flagStay plugin unloaded");
  return 0;
}

class FlagStayZone
{
public:
	FlagStayZone()
	{
		box = false;
		xMax = xMin = yMax = yMin = zMax = zMin = rad = 0;
	}

	bool box;
	float xMax,xMin,yMax,yMin,zMax,zMin;
	float rad;

	std::string message;
	bool pointIn ( float pos[3] )
	{
		if ( box )
		{
			if ( pos[0] > xMax || pos[0] < xMin )
				return false;

			if ( pos[1] > yMax || pos[1] < yMin )
				return false;

			if ( pos[2] > zMax || pos[2] < zMin )
				return false;
		}
		else
		{
			float vec[3];
			vec[0] = pos[0]-xMax;
			vec[1] = pos[1]-yMax;
			vec[2] = pos[2]-zMax;

			float dist = sqrt(vec[0]*vec[0]+vec[1]*vec[1]);
			if ( dist > rad)
				return false;

			if ( pos[2] > zMax || pos[2] < zMin )
				return false;

		}
		return true;
	}

	bool checkFlag ( const char* flag )
	{
		for ( unsigned int i = 0; i < flagList.size(); i++ )
		{
			if ( flagList[i] == flag )
				return true;
		}
		return false;
	}

	std::vector<std::string> flagList;
};

std::vector <FlagStayZone> zoneList;

bool FlagStayZoneHandler::handle ( bzApiString object, bz_CustomMapObjectInfo *data )
{
	if (object != "FLAGSTAYZONE" || !data)
		return false;

	FlagStayZone newZone;

	// parse all the chunks
	for ( unsigned int i = 0; i < data->data.size(); i++ )
	{
		std::string line = data->data.get(i).c_str();

		bzAPIStringList *nubs = bz_newStringList();
		nubs->tokenize(line.c_str()," ",0,true);

		if ( nubs->size() > 0)
		{
			std::string key = bz_toupper(nubs->get(0).c_str());

			if ( key == "BBOX" && nubs->size() > 6)
			{
				newZone.box = true;
				newZone.xMin = (float)atof(nubs->get(1).c_str());
				newZone.xMax = (float)atof(nubs->get(2).c_str());
				newZone.yMin = (float)atof(nubs->get(3).c_str());
				newZone.yMax = (float)atof(nubs->get(4).c_str());
				newZone.zMin = (float)atof(nubs->get(5).c_str());
				newZone.zMax = (float)atof(nubs->get(6).c_str());
			}
			else if ( key == "CYLINDER" && nubs->size() > 5)
			{
				newZone.box = false;
				newZone.rad = (float)atof(nubs->get(5).c_str());
				newZone.xMax =(float)atof(nubs->get(1).c_str());
				newZone.yMax =(float)atof(nubs->get(2).c_str());
				newZone.zMin =(float)atof(nubs->get(3).c_str());
				newZone.zMax =(float)atof(nubs->get(4).c_str());
			}
			else if ( key == "FLAG" && nubs->size() > 1)
			{
				std::string flag = nubs->get(1).c_str();
				newZone.flagList.push_back(flag);
			}
			else if ( key == "MESSAGE" && nubs->size() > 1 )
			{
				newZone.message = nubs->get(1).c_str();
			}
		}
		bz_deleteStringList(nubs);
	}
	zoneList.push_back(newZone);
	return true;
}

void EventHandler::process ( bz_EventData *eventData )
{
	float pos[3] = {0};

	int playerID = -1;

	switch (eventData->eventType)
	{
	case bz_ePlayerUpdateEvent:
		pos[0] = ((bz_PlayerUpdateEventData*)eventData)->pos[0];
		pos[1] = ((bz_PlayerUpdateEventData*)eventData)->pos[1];
		pos[2] = ((bz_PlayerUpdateEventData*)eventData)->pos[2];
		playerID = ((bz_PlayerUpdateEventData*)eventData)->playerID;
		break;

	case bz_eShotFiredEvent:
		pos[0] = ((bz_ShotFiredEventData*)eventData)->pos[0];
		pos[1] = ((bz_ShotFiredEventData*)eventData)->pos[1];
		pos[2] = ((bz_ShotFiredEventData*)eventData)->pos[2];
		playerID = ((bz_ShotFiredEventData*)eventData)->playerID;
		break;
	}

	const char* flagAbrev = bz_getPlayerFlag(playerID);
	if (!flagAbrev)
		return;

	std::vector<FlagStayZone*> validZones;

	// check and see if a zone cares about the current flag
	for ( unsigned int i = 0; i < zoneList.size(); i++ )
	{
		if ( zoneList[i].checkFlag(flagAbrev) )
			validZones.push_back(&zoneList[i]);
	}

	bool insideOne = false;
	for ( unsigned int i = 0; i < validZones.size(); i++ )
	{
		if ( validZones[i]->pointIn(pos) )	// they have taken the flag out of a zone, pop it.
			insideOne = true;
	}

	if (!insideOne)
	{
		bz_removePlayerFlag(playerID);
		if (zoneList[i].message.size())
			bz_sendTextMessage(BZ_SERVER,playerID,zoneList[i].message.c_str());
	}
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<commit_msg>use the last zone the player was in with the flag for the messages<commit_after>// flagStay.cpp : Defines the entry point for the DLL application.
//

#include "bzfsAPI.h"
#include <string>
#include <vector>
#include <map>
#include <math.h>

BZ_GET_PLUGIN_VERSION

class FlagStayZoneHandler : public bz_CustomMapObjectHandler
{
public:
	virtual bool handle ( bzApiString object, bz_CustomMapObjectInfo *data );
};

FlagStayZoneHandler	flagStayZoneHandler;

class EventHandler : public bz_EventHandler
{
public:
	virtual void process ( bz_EventData *eventData );
};

EventHandler eventHandler;

BZF_PLUGIN_CALL int bz_Load ( const char* /*commandLine*/ )
{
  bz_debugMessage(4,"flagStay plugin loaded");
  bz_registerCustomMapObject("FLAGSTAYZONE",&flagStayZoneHandler);

  bz_registerEvent(bz_ePlayerUpdateEvent,&eventHandler);
  return 0;
}

BZF_PLUGIN_CALL int bz_Unload ( void )
{
  bz_removeEvent(bz_ePlayerUpdateEvent,&eventHandler);
  bz_removeCustomMapObject("FLAGSTAYZONE");
  bz_debugMessage(4,"flagStay plugin unloaded");
  return 0;
}

class FlagStayZone
{
public:
	FlagStayZone()
	{
		box = false;
		xMax = xMin = yMax = yMin = zMax = zMin = rad = 0;
	}

	bool box;
	float xMax,xMin,yMax,yMin,zMax,zMin;
	float rad;

	std::string message;
	bool pointIn ( float pos[3] )
	{
		if ( box )
		{
			if ( pos[0] > xMax || pos[0] < xMin )
				return false;

			if ( pos[1] > yMax || pos[1] < yMin )
				return false;

			if ( pos[2] > zMax || pos[2] < zMin )
				return false;
		}
		else
		{
			float vec[3];
			vec[0] = pos[0]-xMax;
			vec[1] = pos[1]-yMax;
			vec[2] = pos[2]-zMax;

			float dist = sqrt(vec[0]*vec[0]+vec[1]*vec[1]);
			if ( dist > rad)
				return false;

			if ( pos[2] > zMax || pos[2] < zMin )
				return false;

		}
		return true;
	}

	bool checkFlag ( const char* flag )
	{
		for ( unsigned int i = 0; i < flagList.size(); i++ )
		{
			if ( flagList[i] == flag )
				return true;
		}
		return false;
	}

	std::vector<std::string> flagList;
};

std::vector <FlagStayZone> zoneList;

bool FlagStayZoneHandler::handle ( bzApiString object, bz_CustomMapObjectInfo *data )
{
	if (object != "FLAGSTAYZONE" || !data)
		return false;

	FlagStayZone newZone;

	// parse all the chunks
	for ( unsigned int i = 0; i < data->data.size(); i++ )
	{
		std::string line = data->data.get(i).c_str();

		bzAPIStringList *nubs = bz_newStringList();
		nubs->tokenize(line.c_str()," ",0,true);

		if ( nubs->size() > 0)
		{
			std::string key = bz_toupper(nubs->get(0).c_str());

			if ( key == "BBOX" && nubs->size() > 6)
			{
				newZone.box = true;
				newZone.xMin = (float)atof(nubs->get(1).c_str());
				newZone.xMax = (float)atof(nubs->get(2).c_str());
				newZone.yMin = (float)atof(nubs->get(3).c_str());
				newZone.yMax = (float)atof(nubs->get(4).c_str());
				newZone.zMin = (float)atof(nubs->get(5).c_str());
				newZone.zMax = (float)atof(nubs->get(6).c_str());
			}
			else if ( key == "CYLINDER" && nubs->size() > 5)
			{
				newZone.box = false;
				newZone.rad = (float)atof(nubs->get(5).c_str());
				newZone.xMax =(float)atof(nubs->get(1).c_str());
				newZone.yMax =(float)atof(nubs->get(2).c_str());
				newZone.zMin =(float)atof(nubs->get(3).c_str());
				newZone.zMax =(float)atof(nubs->get(4).c_str());
			}
			else if ( key == "FLAG" && nubs->size() > 1)
			{
				std::string flag = nubs->get(1).c_str();
				newZone.flagList.push_back(flag);
			}
			else if ( key == "MESSAGE" && nubs->size() > 1 )
			{
				newZone.message = nubs->get(1).c_str();
			}
		}
		bz_deleteStringList(nubs);
	}
	zoneList.push_back(newZone);
	return true;
}

std::map<int,int>	playeIDToZoneMap;

void EventHandler::process ( bz_EventData *eventData )
{
	float pos[3] = {0};

	int playerID = -1;

	switch (eventData->eventType)
	{
	case bz_ePlayerUpdateEvent:
		pos[0] = ((bz_PlayerUpdateEventData*)eventData)->pos[0];
		pos[1] = ((bz_PlayerUpdateEventData*)eventData)->pos[1];
		pos[2] = ((bz_PlayerUpdateEventData*)eventData)->pos[2];
		playerID = ((bz_PlayerUpdateEventData*)eventData)->playerID;
		break;

	case bz_eShotFiredEvent:
		pos[0] = ((bz_ShotFiredEventData*)eventData)->pos[0];
		pos[1] = ((bz_ShotFiredEventData*)eventData)->pos[1];
		pos[2] = ((bz_ShotFiredEventData*)eventData)->pos[2];
		playerID = ((bz_ShotFiredEventData*)eventData)->playerID;
		break;

	default:
		return;
	}

	const char* flagAbrev = bz_getPlayerFlag(playerID);
	if (!flagAbrev)
		return;

	std::vector<FlagStayZone*> validZones;

	// check and see if a zone cares about the current flag
	for ( unsigned int i = 0; i < zoneList.size(); i++ )
	{
		if ( zoneList[i].checkFlag(flagAbrev) )
			validZones.push_back(&zoneList[i]);
	}

	bool insideOne = false;
	for ( unsigned int i = 0; i < validZones.size(); i++ )
	{
		if ( validZones[i]->pointIn(pos) )	// they have taken the flag out of a zone, pop it.
		{
			insideOne = true;
			playeIDToZoneMap[playerID] = i;
		}
	}

	if (!insideOne)
	{
		int lastZone = -1;
		if ( playeIDToZoneMap.find(playerID) !=playeIDToZoneMap.end() )
			lastZone = playeIDToZoneMap[playerID];

		bz_removePlayerFlag(playerID);
		if (lastZone != -1 && zoneList[lastZone].message.size())
			bz_sendTextMessage(BZ_SERVER,playerID,zoneList[i].message.c_str());
	}
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<|endoftext|>


<commit_before>#pragma once

#include <eoslib/memory.h>
#include <eoslib/print.hpp>

namespace eos {

   using ::memset;
   using ::memcpy;

  /**
   *  @defgroup memorycppapi Memory C++ API
   *  @brief Defines common memory functions
   *  @ingroup memoryapi
   *
   *  @{
   */

   class memory
   {
      friend void* malloc(uint32_t size);
      friend void* realloc(void* ptr, uint32_t size);
      friend void free(void* ptr);

   public:
      memory()
      : _offset(0)
      {
         memset(_initial_heap, 0, sizeof(_initial_heap));
      }

   private:
      void* malloc(uint32_t size)
      {
         if (_offset + size + SIZE_MARKER > INITIAL_HEAP_SIZE || size == 0)
            return nullptr;

         buffer_ptr new_buff(&_initial_heap[_offset + SIZE_MARKER], size);
         _offset += size + SIZE_MARKER;
         return new_buff.ptr();
      }

      void* realloc(void* ptr, uint32_t size)
      {
         uint32_t orig_ptr_size = 0;
         const char* const END_OF_BUFFER = _initial_heap + INITIAL_HEAP_SIZE;
         char* const char_ptr = static_cast<char*>(ptr);
         if (ptr != nullptr)
         {
            buffer_ptr orig_buffer(ptr);
            if (orig_buffer.size_ptr() >= _initial_heap && ptr < END_OF_BUFFER)
            {
               orig_ptr_size = orig_buffer.size();
               // is the passed in pointer valid
               char* const orig_buffer_end = orig_buffer.end();
               if (orig_buffer_end < END_OF_BUFFER)
               {
                  // is there enough memory to allocate new buffer
                  if (ptr >= END_OF_BUFFER - size)
                  {
                     // not handling in current implementation
                     return nullptr;
                  }

                  const int32_t diff = size - orig_ptr_size;
                  if (diff < 0)
                  {
                     memset(orig_buffer_end + diff, 0, -diff);
                     // if ptr was the last allocated buffer, we can contract
                     if (orig_buffer_end == &_initial_heap[_offset])
                     {
                        _offset += diff;
                     }
                     // else current implementation doesn't worry about freeing excess memory

                     return ptr;
                  }
                  // if ptr was the last allocated buffer, we can expand
                  else if (orig_buffer_end == &_initial_heap[_offset])
                  {
                     orig_buffer.size(size);
                     _offset += diff;

                     return ptr;
                  }
                  else if (diff == 0)
                     return ptr;
               }
               else
               {
                  orig_ptr_size = 0;
               }
            }
         }

         char* new_alloc = static_cast<char*>(malloc(size));

         const uint32_t copy_size = (size < orig_ptr_size) ? size : orig_ptr_size;
         if (copy_size > 0)
         {
            memcpy(new_alloc, ptr, copy_size);
            free (ptr);
         }

         return new_alloc;
      }

      void free(void* )
      {
         // currently no-op
      }

      class buffer_ptr
      {
      public:
         buffer_ptr(void* ptr)
         : _ptr(static_cast<char*>(ptr))
         , _size(*(uint32_t*)(static_cast<char*>(ptr) - SIZE_MARKER))
         {
         }

         buffer_ptr(void* ptr, uint32_t buff_size)
         : _ptr(static_cast<char*>(ptr))
         {
            size(buff_size);
         }

         const void* size_ptr()
         {
            return _ptr - SIZE_MARKER;
         }

         uint32_t size()
         {
            return _size;
         }

         void size(uint32_t val)
         {
            *reinterpret_cast<uint32_t*>(_ptr - SIZE_MARKER) = val;
            _size = val;
         }

         char* end()
         {
            return _ptr + _size;
         }

         char* ptr()
         {
            return _ptr;
         }
      private:

         char* const _ptr;
         uint32_t _size;
      };

      static const uint32_t SIZE_MARKER = sizeof(uint32_t);
      static const uint32_t INITIAL_HEAP_SIZE = 8192;//32768;
      char _initial_heap[INITIAL_HEAP_SIZE];
      uint32_t _offset;
   } memory_heap;

  /**
   * Allocate a block of memory.
   * @brief Allocate a block of memory.
   * @param size  Size of memory block
   *
   * Example:
   * @code
   * uint64_t* int_buffer = malloc(500 * sizeof(uint64_t));
   * @endcode
   */
   inline void* malloc(uint32_t size)
   {
      return memory_heap.malloc(size);
   }

   /**
    * Allocate a block of memory.
    * @brief Allocate a block of memory.
    * @param size  Size of memory block
    *
    * Example:
    * @code
    * uint64_t* int_buffer = malloc(500 * sizeof(uint64_t));
    * ...
    * uint64_t* bigger_int_buffer = realloc(int_buffer, 600 * sizeof(uint64_t));
    * @endcode
    */

   inline void* realloc(void* ptr, uint32_t size)
   {
      return memory_heap.realloc(ptr, size);
   }

   /**
    * Free a block of memory.
    * @brief Free a block of memory.
    * @param ptr  Pointer to memory block to free.
    *
    * Example:
    * @code
    * uint64_t* int_buffer = malloc(500 * sizeof(uint64_t));
    * ...
    * free(int_buffer);
    * @endcode
    */
    inline void free(void* ptr)
    {
       return memory_heap.free(ptr);
    }
   /// @} /// mathcppapi
}
<commit_msg>Refactored existing handling of malloc and realloc to add new pages of memory.  Currently, memory pages are fabricated.<commit_after>#pragma once

#include <eoslib/memory.h>
#include <eoslib/print.hpp>

namespace eos {

   using ::memset;
   using ::memcpy;

  /**
   *  @defgroup memorycppapi Memory C++ API
   *  @brief Defines common memory functions
   *  @ingroup memoryapi
   *
   *  @{
   */

   class memory_manager
   {
   friend void* malloc(uint32_t size);
   friend void* realloc(void* ptr, uint32_t size);
   friend void free(void* ptr);
   public:
      memory_manager()
      : _current_heap(0)
      {
      }

   private:
      void* malloc(uint32_t size)
      {
         // first pass of loop never has to initialize the slot in _available_heap
         uint32_t needs_init = 0;
         char* buffer = nullptr;
         uint32_t current_heap = _current_heap;
         for (;current_heap < HEAPS_SIZE; ++current_heap)
         {
            memory& current = _available_heaps[current_heap];
            if(!current.is_init())
            {
               char* new_heap = nullptr;
               if (current_heap == 0)
               {
                  memset(_initial_heap, 0, sizeof(_initial_heap));
                  current.init(_initial_heap, INITIAL_HEAP_SIZE);
               }
               else
               {
                  // REMOVE logic, just using to test out multiple heap logic till memory can be allocated
                  char* const new_heap = &_initial_heap[INITIAL_HEAP_SIZE + NEW_HEAP_SIZE * (current_heap - 1)];
                  _available_heaps[current_heap].init(new_heap, NEW_HEAP_SIZE);
               }
            }
            buffer = current.malloc(size);
            if (buffer != nullptr)
               break;
         }

         // only update the current_heap if memory was allocated
         if (buffer != nullptr)
         {
            _current_heap = current_heap;
         }

         return buffer;
      }

      void* realloc(void* ptr, uint32_t size)
      {
         char* realloc_ptr = nullptr;
         uint32_t orig_ptr_size = 0;
         if (ptr != nullptr)
         {
            char* const char_ptr = static_cast<char*>(ptr);
            for (memory* realloc_heap = _available_heaps; realloc_heap < _available_heaps + HEAPS_SIZE && realloc_heap->is_init(); ++realloc_heap)
            {
               if (realloc_heap->is_in_heap(char_ptr))
               {
                  realloc_ptr = realloc_heap->realloc_in_place(char_ptr, size, &orig_ptr_size);

                  if (realloc_ptr != nullptr)
                     return realloc_ptr;
                  else
                     break;
               }
            }
         }

         char* new_alloc = static_cast<char*>(malloc(size));

         const uint32_t copy_size = (size < orig_ptr_size) ? size : orig_ptr_size;
         if (copy_size > 0)
         {
            memcpy(new_alloc, ptr, copy_size);
            free (ptr);
         }

         return new_alloc;
      }

      void free(void* )
      {
         // currently no-op
      }

      class memory
      {
      public:
         memory()
         : _heap_size(0)
         , _heap(nullptr)
         , _offset(0)
         {
         }

         void init(char* const mem_heap, uint32_t size)
         {
            _heap_size = size;
            _heap = mem_heap;
            _offset = 0;
            memset(_heap, 0, _heap_size);
         }

         uint32_t is_init() const
         {
            return _heap != nullptr;
         }

         uint32_t is_in_heap(const char* const ptr) const
         {
            const char* const END_OF_BUFFER = _heap + _heap_size;
            const char* const FIRST_PTR_OF_BUFFER = _heap + SIZE_MARKER;
            return ptr >= FIRST_PTR_OF_BUFFER && ptr < END_OF_BUFFER;
         }

         uint32_t is_capacity_remaining() const
         {
            return _offset + SIZE_MARKER < _heap_size;
         }

         char* malloc(uint32_t size)
         {
            if (_offset + size + SIZE_MARKER > _heap_size || size == 0)
            {
               return nullptr;
            }

            buffer_ptr new_buff(&_heap[_offset + SIZE_MARKER], size);
            _offset += size + SIZE_MARKER;
            return new_buff.ptr();
         }

         char* realloc_in_place(char* const ptr, uint32_t size, uint32_t* orig_ptr_size)
         {
            const char* const END_OF_BUFFER = _heap + _heap_size;

            buffer_ptr orig_buffer(ptr);
            *orig_ptr_size = orig_buffer.size();
            // is the passed in pointer valid
            char* const orig_buffer_end = orig_buffer.end();
            if (orig_buffer_end > END_OF_BUFFER)
            {
               *orig_ptr_size = 0;
               return nullptr;
            }

            if (ptr > END_OF_BUFFER - size)
            {
               // cannot resize in place
               return nullptr;
            }

            const int32_t diff = size - *orig_ptr_size;
            if (diff < 0)
            {
               memset(orig_buffer_end + diff, 0, -diff);
               // if ptr was the last allocated buffer, we can contract
               if (orig_buffer_end == &_heap[_offset])
               {
                  _offset += diff;
               }
               // else current implementation doesn't worry about freeing excess memory

               return ptr;
            }
            // if ptr was the last allocated buffer, we can expand
            else if (orig_buffer_end == &_heap[_offset])
            {
               orig_buffer.size(size);
               _offset += diff;

               return ptr;
            }
            else if (diff == 0)
            {
               return ptr;
            }

            // could not resize in place
            return nullptr;
         }

         void free(char* )
         {
            // currently no-op
         }

      private:
         class buffer_ptr
         {
         public:
            buffer_ptr(void* ptr)
            : _ptr(static_cast<char*>(ptr))
            , _size(*(uint32_t*)(static_cast<char*>(ptr) - SIZE_MARKER))
            {
            }

            buffer_ptr(void* ptr, uint32_t buff_size)
            : _ptr(static_cast<char*>(ptr))
            {
               size(buff_size);
            }

            const void* size_ptr()
            {
               return _ptr - SIZE_MARKER;
            }

            uint32_t size()
            {
               return _size;
            }

            void size(uint32_t val)
            {
               *reinterpret_cast<uint32_t*>(_ptr - SIZE_MARKER) = val;
               _size = val;
            }

            char* end()
            {
               return _ptr + _size;
            }

            char* ptr()
            {
               return _ptr;
            }
         private:

            char* const _ptr;
            uint32_t _size;
         };

         uint32_t _heap_size;
         char* _heap;
         uint32_t _offset;
      };

      static const uint32_t SIZE_MARKER = sizeof(uint32_t);
      static const uint32_t INITIAL_HEAP_SIZE = 8192;//32768;
      static const uint32_t NEW_HEAP_SIZE = 1024; // should be 65536
      static const uint32_t HEAPS_SIZE = 4; // _initial_heap plus 3 pages (64K each)
      // should be just INITIAL_HEAP_SIZE, adding extra space for testing multiple buffers
      char _initial_heap[INITIAL_HEAP_SIZE + NEW_HEAP_SIZE * (HEAPS_SIZE - 1)];
      memory _available_heaps[HEAPS_SIZE];
      uint32_t _current_heap;
   } memory_heap;

  /**
   * Allocate a block of memory.
   * @brief Allocate a block of memory.
   * @param size  Size of memory block
   *
   * Example:
   * @code
   * uint64_t* int_buffer = malloc(500 * sizeof(uint64_t));
   * @endcode
   */
   inline void* malloc(uint32_t size)
   {
      return memory_heap.malloc(size);
   }

   /**
    * Allocate a block of memory.
    * @brief Allocate a block of memory.
    * @param size  Size of memory block
    *
    * Example:
    * @code
    * uint64_t* int_buffer = malloc(500 * sizeof(uint64_t));
    * ...
    * uint64_t* bigger_int_buffer = realloc(int_buffer, 600 * sizeof(uint64_t));
    * @endcode
    */

   inline void* realloc(void* ptr, uint32_t size)
   {
      return memory_heap.realloc(ptr, size);
   }

   /**
    * Free a block of memory.
    * @brief Free a block of memory.
    * @param ptr  Pointer to memory block to free.
    *
    * Example:
    * @code
    * uint64_t* int_buffer = malloc(500 * sizeof(uint64_t));
    * ...
    * free(int_buffer);
    * @endcode
    */
    inline void free(void* ptr)
    {
       return memory_heap.free(ptr);
    }
   /// @} /// mathcppapi
}
<|endoftext|>


<commit_before>#pragma once
#include "config.hpp"
#include <inttypes.h>

struct Buzzer
{
  Buzzer()
  {
    // phase correct PWM
    TCCR0A |= _BV(WGM00);
    //TCCR0B |= _BV(WGM02);
    // 01 PWM
    TCCR0A |= _BV(COM0B1);
    // frequency ~1kHz
    OCR0B = 20;
    // output mode
    DDRB |= _BV(PB1);
  }

  void on()
  {
    TCCR0B |= _BV(CS00); // prescaler = 1
  }

  void off()
  {
    TCCR0B &= ~ ( _BV(CS02) | _BV(CS01) | _BV(CS00) );  // prescaler = 0 (i.e. stop clock)
  }
};
<commit_msg>normal mode: ~600Hz out<commit_after>#pragma once
#include "config.hpp"
#include <inttypes.h>

struct Buzzer
{
  Buzzer()
  {
    // normal mode
    TCCR0A |= 0u;
    // clear on compare
    TCCR0A |= _BV(COM0B0);
    //TCCR0B |= _BV(WGM02);
    // volume 0-255
    OCR0B = 100;
    // output mode
    DDRB |= _BV(PB1);
  }

  void on()
  {
    // ~586 [Hz]
    TCCR0B |= _BV(CS01); // prescaler = 8
  }

  void off()
  {
    TCCR0B &= ~ ( _BV(CS02) | _BV(CS01) | _BV(CS00) );  // prescaler = 0 (i.e. stop clock)
  }
};
<|endoftext|>