<commit_before>#include "pb_conn.h"
#include "pink_define.h"
#include "worker_thread.h"
#include "xdebug.h"

#include <string>

namespace pink {

PbConn::PbConn(const int fd, const std::string &ip_port) :
  PinkConn(fd, ip_port),
  header_len_(-1),
  cur_pos_(0),
  rbuf_len_(0),
  connStatus_(kHeader),
  wbuf_len_(0),
  wbuf_pos_(0)
{
  rbuf_ = (char *)malloc(sizeof(char) * PB_MAX_MESSAGE);
  wbuf_ = (char *)malloc(sizeof(char) * PB_MAX_MESSAGE);
}

PbConn::~PbConn()
{
  free(rbuf_);
  free(wbuf_);
}

ReadStatus PbConn::GetRequest()
{
  ssize_t nread = 0;
  nread = read(fd(), rbuf_ + rbuf_len_, PB_MAX_MESSAGE);

  if (nread == -1) {
    if (errno == EAGAIN) {
      return kReadHalf;
    } else {
      return kReadError;
    }
  } else if (nread == 0) {
    return kReadClose;
  }

  uint32_t integer = 0;
  bool flag = true;

  if (nread) {
    rbuf_len_ += nread;
    while (flag) {
      switch (connStatus_) {
      case kHeader:
        if (rbuf_len_ - cur_pos_ >= COMMAND_HEADER_LENGTH) {
          memcpy((char *)(&integer), rbuf_ + cur_pos_, sizeof(uint32_t));
          header_len_ = ntohl(integer);
          log_info("Header_len %u", header_len_);
          connStatus_ = kPacket;
          cur_pos_ += COMMAND_HEADER_LENGTH;
        } else {
          flag = false;
        }
        break;
      case kPacket:
        if (rbuf_len_ >= header_len_ + COMMAND_HEADER_LENGTH) {
          cur_pos_ += header_len_;
          log_info("k Packet cur_pos_ %d rbuf_len_ %d", cur_pos_, rbuf_len_);
          connStatus_ = kComplete;
        } else {
          flag = false;
        }
        break;
      case kComplete:
        DealMessage();
        connStatus_ = kHeader;
        log_info("%d %d", cur_pos_, rbuf_len_);
        if (cur_pos_ == rbuf_len_) {
          cur_pos_ = 0;
          rbuf_len_ = 0;
        }
        return kReadAll;
        /*
         * Add this switch case just for delete compile warning
         */
      case kBuildObuf:
        break;

      case kWriteObuf:
        break;
      }
    }
  }
  return kReadHalf;
}

WriteStatus PbConn::SendReply()
{
  BuildObuf();
  ssize_t nwritten = 0;
  while (wbuf_len_ > 0) {
    nwritten = write(fd(), wbuf_ + wbuf_pos_, wbuf_len_ - wbuf_pos_);
    if (nwritten <= 0) {
      break;
    }
    wbuf_pos_ += nwritten;
    if (wbuf_pos_ == wbuf_len_) {
      wbuf_len_ = 0;
      wbuf_pos_ = 0;
    }
  }
  if (nwritten == -1) {
    if (errno == EAGAIN) {
      return kWriteHalf;
    } else {
      // Here we should close the connection
      return kWriteError;
    }
  }
  if (wbuf_len_ == 0) {
    return kWriteAll;
  } else {
    return kWriteHalf;
  }
}

Status PbConn::BuildObuf()
{
  wbuf_len_ = res_->ByteSize();
  res_->SerializeToArray(wbuf_ + 4, wbuf_len_);
  uint32_t u;
  u = htonl(wbuf_len_);
  memcpy(wbuf_, &u, sizeof(uint32_t));
  wbuf_len_ += COMMAND_HEADER_LENGTH;

  return Status::OK();
}

}
<commit_msg>Revert "Fix bug of wbuf_pos without initialization"<commit_after>#include "pb_conn.h"
#include "pink_define.h"
#include "worker_thread.h"
#include "xdebug.h"

#include <string>

namespace pink {

PbConn::PbConn(const int fd, const std::string &ip_port) :
  PinkConn(fd, ip_port),
  header_len_(-1),
  cur_pos_(0),
  rbuf_len_(0),
  connStatus_(kHeader)
{
  rbuf_ = (char *)malloc(sizeof(char) * PB_MAX_MESSAGE);
  wbuf_ = (char *)malloc(sizeof(char) * PB_MAX_MESSAGE);
}

PbConn::~PbConn()
{
  free(rbuf_);
  free(wbuf_);
}

ReadStatus PbConn::GetRequest()
{
  ssize_t nread = 0;
  nread = read(fd(), rbuf_ + rbuf_len_, PB_MAX_MESSAGE);

  if (nread == -1) {
    if (errno == EAGAIN) {
      return kReadHalf;
    } else {
      return kReadError;
    }
  } else if (nread == 0) {
    return kReadClose;
  }

  uint32_t integer = 0;
  bool flag = true;

  if (nread) {
    rbuf_len_ += nread;
    while (flag) {
      switch (connStatus_) {
      case kHeader:
        if (rbuf_len_ - cur_pos_ >= COMMAND_HEADER_LENGTH) {
          memcpy((char *)(&integer), rbuf_ + cur_pos_, sizeof(uint32_t));
          header_len_ = ntohl(integer);
          log_info("Header_len %u", header_len_);
          connStatus_ = kPacket;
          cur_pos_ += COMMAND_HEADER_LENGTH;
        } else {
          flag = false;
        }
        break;
      case kPacket:
        if (rbuf_len_ >= header_len_ + COMMAND_HEADER_LENGTH) {
          cur_pos_ += header_len_;
          log_info("k Packet cur_pos_ %d rbuf_len_ %d", cur_pos_, rbuf_len_);
          connStatus_ = kComplete;
        } else {
          flag = false;
        }
        break;
      case kComplete:
        DealMessage();
        connStatus_ = kHeader;
        log_info("%d %d", cur_pos_, rbuf_len_);
        if (cur_pos_ == rbuf_len_) {
          cur_pos_ = 0;
          rbuf_len_ = 0;
        }
        return kReadAll;
        /*
         * Add this switch case just for delete compile warning
         */
      case kBuildObuf:
        break;

      case kWriteObuf:
        break;
      }
    }
  }
  return kReadHalf;
}

WriteStatus PbConn::SendReply()
{
  BuildObuf();
  ssize_t nwritten = 0;
  while (wbuf_len_ > 0) {
    nwritten = write(fd(), wbuf_ + wbuf_pos_, wbuf_len_ - wbuf_pos_);
    if (nwritten <= 0) {
      break;
    }
    wbuf_pos_ += nwritten;
    if (wbuf_pos_ == wbuf_len_) {
      wbuf_len_ = 0;
      wbuf_pos_ = 0;
    }
  }
  if (nwritten == -1) {
    if (errno == EAGAIN) {
      return kWriteHalf;
    } else {
      // Here we should close the connection
      return kWriteError;
    }
  }
  if (wbuf_len_ == 0) {
    return kWriteAll;
  } else {
    return kWriteHalf;
  }
}

Status PbConn::BuildObuf()
{
  wbuf_len_ = res_->ByteSize();
  res_->SerializeToArray(wbuf_ + 4, wbuf_len_);
  uint32_t u;
  u = htonl(wbuf_len_);
  memcpy(wbuf_, &u, sizeof(uint32_t));
  wbuf_len_ += COMMAND_HEADER_LENGTH;

  return Status::OK();
}

}
<|endoftext|>


<commit_before>#include "pbview.h"

#include <cinttypes>
#include <cstdio>
#include <cstring>
#include <ncurses.h>
#include <iostream>
#include <sstream>

#include "config.h"
#include "configcontainer.h"
#include "dllist.h"
#include "download.h"
#include "fmtstrformatter.h"
#include "help.h"
#include "listformatter.h"
#include "logger.h"
#include "pbcontroller.h"
#include "strprintf.h"
#include "utils.h"

using namespace newsboat;

namespace podboat {

PbView::PbView(PbController* c)
	: update_view(true)
	, ctrl(c)
	, dllist_form(dllist_str)
	, help_form(help_str)
	, keys(0)
	, colorman(ctrl->get_colormanager())
	, downloads_list("dls", dllist_form,
		  ctrl->get_cfgcont()->get_configvalue_as_int("scrolloff"))
	, help_textview("helptext", help_form)
{
	if (getenv("ESCDELAY") == nullptr) {
		set_escdelay(25);
	}
}

PbView::~PbView()
{
	Stfl::reset();
}

void PbView::run(bool auto_download, bool wrap_scroll)
{
	bool quit = false;

	// Make sure curses is initialized
	dllist_form.run(-3);
	// Hide cursor using curses
	curs_set(0);

	set_dllist_keymap_hint();

	do {
		if (update_view) {
			const double total_kbps = ctrl->get_total_kbps();
			const auto speed = get_speed_human_readable(total_kbps);

			auto title = strprintf::fmt(
					_("Queue (%u downloads in progress, %u total) - %.2f %s total"),
					static_cast<unsigned int>(ctrl->downloads_in_progress()),
					static_cast<unsigned int>(ctrl->downloads().size()),
					speed.first,
					speed.second);

			if (ctrl->get_maxdownloads() > 1) {
				title += strprintf::fmt(_(" - %u parallel downloads"), ctrl->get_maxdownloads());
			}

			dllist_form.set("head", title);

			LOG(Level::DEBUG,
				"PbView::run: updating view... "
				"downloads().size() "
				"= %" PRIu64,
				static_cast<uint64_t>(ctrl->downloads().size()));

			ListFormatter listfmt;
			const std::string line_format =
				ctrl->get_cfgcont()->get_configvalue("podlist-format");

			dllist_form.run(-3); // compute all widget dimensions
			const unsigned int width = downloads_list.get_width();

			unsigned int i = 0;
			for (const auto& dl : ctrl->downloads()) {
				auto lbuf = format_line(line_format, dl, i, width);
				listfmt.add_line(lbuf);
				i++;
			}

			downloads_list.stfl_replace_lines(listfmt);

			// If there's no status message, we know there's no error to show
			// Thus, it's safe to replace with the download's status
			if (i >= 1 && dllist_form.get("msg").empty()) {
				const auto idx = downloads_list.get_position();
				dllist_form.set("msg", ctrl->downloads()[idx].status_msg());
			}

			update_view = false;
		}

		const char* event = dllist_form.run(500);

		if (auto_download) {
			if (ctrl->get_maxdownloads() >
				ctrl->downloads_in_progress()) {
				ctrl->start_downloads();
			}
		}

		if (!event || strcmp(event, "TIMEOUT") == 0) {
			continue;
		}

		if (strcmp(event, "RESIZE") == 0) {
			handle_resize();
			continue;
		}

		Operation op = keys->get_operation(event, "podboat");

		if (dllist_form.get("msg").length() > 0) {
			dllist_form.set("msg", "");
			update_view = true;
		}

		switch (op) {
		case OP_REDRAW:
			Stfl::reset();
			break;
		case OP_PREV:
		case OP_SK_UP:
			downloads_list.move_up(wrap_scroll);
			update_view = true;
			break;
		case OP_NEXT:
		case OP_SK_DOWN:
			downloads_list.move_down(wrap_scroll);
			update_view = true;
			break;
		case OP_SK_HOME:
			downloads_list.move_to_first();
			update_view = true;
			break;
		case OP_SK_END:
			downloads_list.move_to_last();
			update_view = true;
			break;
		case OP_SK_PGUP:
			downloads_list.move_page_up(wrap_scroll);
			update_view = true;
			break;
		case OP_SK_PGDOWN:
			downloads_list.move_page_down(wrap_scroll);
			update_view = true;
			break;
		case OP_PB_TOGGLE_DLALL:
			auto_download = !auto_download;
			break;
		case OP_HARDQUIT:
		case OP_QUIT:
			if (ctrl->downloads_in_progress() > 0) {
				dllist_form.set("msg", _("Error: can't quit: download(s) in progress."));
				update_view = true;
			} else {
				quit = true;
			}
			break;
		case OP_PB_MOREDL:
			ctrl->increase_parallel_downloads();
			break;
		case OP_PB_LESSDL:
			ctrl->decrease_parallel_downloads();
			break;
		case OP_PB_DOWNLOAD: {
			if (ctrl->downloads().size() >= 1) {
				const auto idx = downloads_list.get_position();
				auto& item = ctrl->downloads()[idx];
				if (item.status() != DlStatus::DOWNLOADING) {
					ctrl->start_download(item);
				}
			}
		}
		break;
		case OP_PB_PLAY: {
			if (ctrl->downloads().size() >= 1) {
				const auto idx = downloads_list.get_position();
				DlStatus status =
					ctrl->downloads()[idx].status();
				if (status == DlStatus::FINISHED ||
					status == DlStatus::PLAYED ||
					status == DlStatus::READY) {
					ctrl->play_file(ctrl->downloads()[idx]
						.filename());
					ctrl->downloads()[idx].set_status(
						DlStatus::PLAYED);
				} else {
					dllist_form.set("msg",
						_("Error: download needs to be "
							"finished before the file "
							"can be played."));
				}
			}
		}
		break;
		case OP_PB_MARK_FINISHED: {
			auto& downloads = ctrl->downloads();
			if (downloads.size() >= 1) {
				const auto idx = downloads_list.get_position();
				DlStatus status =
					downloads[idx].status();
				if (status == DlStatus::PLAYED) {
					downloads[idx].set_status(DlStatus::FINISHED);
					if (idx + 1 < downloads.size()) {
						downloads_list.set_position(idx + 1);
					}
				}
			}
		}
		break;
		case OP_PB_CANCEL: {
			if (ctrl->downloads().size() >= 1) {
				const auto idx = downloads_list.get_position();
				if (ctrl->downloads()[idx].status() ==
					DlStatus::DOWNLOADING) {
					ctrl->downloads()[idx].set_status(
						DlStatus::CANCELLED);
				}
			}
		}
		break;
		case OP_PB_DELETE: {
			auto& downloads = ctrl->downloads();
			if (downloads.size() >= 1) {
				const auto idx = downloads_list.get_position();
				if (downloads[idx].status() !=
					DlStatus::DOWNLOADING) {
					downloads[idx].set_status(DlStatus::DELETED);
					if (idx + 1 < downloads.size()) {
						downloads_list.set_position(idx + 1);
					}
				}
			}
		}
		break;
		case OP_PB_PURGE:
			if (ctrl->downloads_in_progress() > 0) {
				dllist_form.set("msg",
					_("Error: unable to perform operation: "
						"download(s) in progress."));
			} else {
				ctrl->purge_queue();
			}
			update_view = true;
			break;
		case OP_HELP:
			run_help();
			break;
		default:
			break;
		}

	} while (!quit);
}

void PbView::handle_resize()
{
	std::vector<std::reference_wrapper<newsboat::Stfl::Form>> forms = {dllist_form, help_form};
	for (const auto& form : forms) {
		form.get().run(-3);
	}
	update_view = true;
}

void PbView::apply_colors_to_all_forms()
{
	using namespace std::placeholders;
	colorman.apply_colors(std::bind(&newsboat::Stfl::Form::set, &dllist_form, _1,
			_2));
	colorman.apply_colors(std::bind(&newsboat::Stfl::Form::set, &help_form, _1,
			_2));
}

std::pair<double, std::string> PbView::get_speed_human_readable(double kbps)
{
	if (kbps < 1024) {
		return std::make_pair(kbps, _("KB/s"));
	} else if (kbps < 1024 * 1024) {
		return std::make_pair(kbps / 1024, _("MB/s"));
	} else {
		return std::make_pair(kbps / 1024 / 1024, _("GB/s"));
	}
}

void PbView::run_help()
{
	set_help_keymap_hint();

	help_form.set("head", _("Help"));

	const auto descs = keys->get_keymap_descriptions("podboat");

	ListFormatter listfmt;

	for (const auto& desc : descs) {
		const std::string descline = strprintf::fmt("%-7s %-23s %s",
				desc.key,
				desc.cmd,
				desc.desc);

		listfmt.add_line(descline);
	}

	help_textview.stfl_replace_lines(listfmt.get_lines_count(),
		listfmt.format_list());

	bool quit = false;

	do {
		const char* event = help_form.run(0);
		if (!event) {
			continue;
		}

		if (strcmp(event, "RESIZE") == 0) {
			handle_resize();
			continue;
		}

		Operation op = keys->get_operation(event, "help");

		switch (op) {
		case OP_SK_UP:
			help_textview.scroll_up();
			break;
		case OP_SK_DOWN:
			help_textview.scroll_down();
			break;
		case OP_SK_HOME:
			help_textview.scroll_to_top();
			break;
		case OP_SK_END:
			help_textview.scroll_to_bottom();
			break;
		case OP_SK_PGUP:
			help_textview.scroll_page_up();
			break;
		case OP_SK_PGDOWN:
			help_textview.scroll_page_down();
			break;
		case OP_HARDQUIT:
		case OP_QUIT:
			quit = true;
			break;
		default:
			break;
		}
	} while (!quit);
}

std::string PbView::prepare_keymaphint(KeyMapHintEntry* hints)
{
	std::string keymap_hint;
	for (int i = 0; hints[i].op != OP_NIL; ++i) {
		std::string bound_keys = utils::join(keys->get_keys(hints[i].op, "podboat"),
				",");
		if (bound_keys.empty()) {
			bound_keys = "<none>";
		}
		keymap_hint.append(bound_keys);
		keymap_hint.append(":");
		keymap_hint.append(hints[i].text);
		keymap_hint.append(" ");
	}
	return keymap_hint;
}

void PbView::set_help_keymap_hint()
{
	static KeyMapHintEntry hints[] = {{OP_QUIT, _("Quit")}, {OP_NIL, nullptr}};
	std::string keymap_hint = prepare_keymaphint(hints);
	help_form.set("help", keymap_hint);
}

void PbView::set_dllist_keymap_hint()
{
	static KeyMapHintEntry hints[] = {{OP_QUIT, _("Quit")},
		{OP_PB_DOWNLOAD, _("Download")},
		{OP_PB_CANCEL, _("Cancel")},
		{OP_PB_DELETE, _("Delete")},
		{OP_PB_PURGE, _("Purge Finished")},
		{OP_PB_TOGGLE_DLALL, _("Toggle Automatic Download")},
		{OP_PB_PLAY, _("Play")},
		{OP_PB_MARK_FINISHED, _("Mark as Finished")},
		{OP_HELP, _("Help")},
		{OP_NIL, nullptr}
	};

	std::string keymap_hint = prepare_keymaphint(hints);
	dllist_form.set("help", keymap_hint);
}

std::string PbView::format_line(const std::string& podlist_format,
	const Download& dl,
	unsigned int pos,
	unsigned int width)
{
	FmtStrFormatter fmt;

	const double speed_kbps = dl.kbps();
	const auto speed = get_speed_human_readable(speed_kbps);

	fmt.register_fmt('i', strprintf::fmt("%u", pos + 1));
	fmt.register_fmt('d',
		strprintf::fmt("%.1f", dl.current_size() / (1024 * 1024)));
	fmt.register_fmt(
		't', strprintf::fmt("%.1f", dl.total_size() / (1024 * 1024)));
	fmt.register_fmt('p', strprintf::fmt("%.1f", dl.percents_finished()));
	fmt.register_fmt('k', strprintf::fmt("%.2f", speed_kbps));
	fmt.register_fmt('K', strprintf::fmt("%.2f %s", speed.first, speed.second));
	fmt.register_fmt('S', strprintf::fmt("%s", dl.status_text()));
	fmt.register_fmt('u', strprintf::fmt("%s", dl.url()));
	fmt.register_fmt('F', strprintf::fmt("%s", dl.filename()));
	fmt.register_fmt('b', strprintf::fmt("%s", dl.basename()));

	auto formattedLine = fmt.do_format(podlist_format, width);
	formattedLine = utils::quote_for_stfl(formattedLine);
	return formattedLine;
}

} // namespace podboat
<commit_msg>Podboat: Only regenerate the full downloads list if something changed<commit_after>#include "pbview.h"

#include <cinttypes>
#include <cstdio>
#include <cstring>
#include <ncurses.h>
#include <iostream>
#include <sstream>

#include "config.h"
#include "configcontainer.h"
#include "dllist.h"
#include "download.h"
#include "fmtstrformatter.h"
#include "help.h"
#include "listformatter.h"
#include "logger.h"
#include "pbcontroller.h"
#include "strprintf.h"
#include "utils.h"

using namespace newsboat;

namespace podboat {

PbView::PbView(PbController* c)
	: update_view(true)
	, ctrl(c)
	, dllist_form(dllist_str)
	, help_form(help_str)
	, keys(0)
	, colorman(ctrl->get_colormanager())
	, downloads_list("dls", dllist_form,
		  ctrl->get_cfgcont()->get_configvalue_as_int("scrolloff"))
	, help_textview("helptext", help_form)
{
	if (getenv("ESCDELAY") == nullptr) {
		set_escdelay(25);
	}
}

PbView::~PbView()
{
	Stfl::reset();
}

void PbView::run(bool auto_download, bool wrap_scroll)
{
	bool quit = false;

	// Make sure curses is initialized
	dllist_form.run(-3);
	// Hide cursor using curses
	curs_set(0);

	set_dllist_keymap_hint();

	do {
		if (update_view) {
			const double total_kbps = ctrl->get_total_kbps();
			const auto speed = get_speed_human_readable(total_kbps);

			auto title = strprintf::fmt(
					_("Queue (%u downloads in progress, %u total) - %.2f %s total"),
					static_cast<unsigned int>(ctrl->downloads_in_progress()),
					static_cast<unsigned int>(ctrl->downloads().size()),
					speed.first,
					speed.second);

			if (ctrl->get_maxdownloads() > 1) {
				title += strprintf::fmt(_(" - %u parallel downloads"), ctrl->get_maxdownloads());
			}

			dllist_form.set("head", title);

			LOG(Level::DEBUG,
				"PbView::run: updating view... "
				"downloads().size() "
				"= %" PRIu64,
				static_cast<uint64_t>(ctrl->downloads().size()));

			ListFormatter listfmt;
			const std::string line_format =
				ctrl->get_cfgcont()->get_configvalue("podlist-format");

			dllist_form.run(-3); // compute all widget dimensions
			const unsigned int width = downloads_list.get_width();

			unsigned int i = 0;
			for (const auto& dl : ctrl->downloads()) {
				auto lbuf = format_line(line_format, dl, i, width);
				listfmt.add_line(lbuf);
				i++;
			}

			downloads_list.stfl_replace_lines(listfmt);

			update_view = false;
		}

		// If there's no status message, we know there's no error to show
		// Thus, it's safe to replace with the download's status
		if (dllist_form.get("msg").empty() && ctrl->downloads().size() > 0) {
			const auto idx = downloads_list.get_position();
			dllist_form.set("msg", ctrl->downloads()[idx].status_msg());
		}

		const char* event = dllist_form.run(500);

		if (auto_download) {
			if (ctrl->get_maxdownloads() >
				ctrl->downloads_in_progress()) {
				ctrl->start_downloads();
			}
		}

		if (!event || strcmp(event, "TIMEOUT") == 0) {
			continue;
		}

		if (strcmp(event, "RESIZE") == 0) {
			handle_resize();
			continue;
		}

		Operation op = keys->get_operation(event, "podboat");

		if (dllist_form.get("msg").length() > 0) {
			dllist_form.set("msg", "");
			update_view = true;
		}

		switch (op) {
		case OP_REDRAW:
			Stfl::reset();
			break;
		case OP_PREV:
		case OP_SK_UP:
			downloads_list.move_up(wrap_scroll);
			break;
		case OP_NEXT:
		case OP_SK_DOWN:
			downloads_list.move_down(wrap_scroll);
			break;
		case OP_SK_HOME:
			downloads_list.move_to_first();
			break;
		case OP_SK_END:
			downloads_list.move_to_last();
			break;
		case OP_SK_PGUP:
			downloads_list.move_page_up(wrap_scroll);
			break;
		case OP_SK_PGDOWN:
			downloads_list.move_page_down(wrap_scroll);
			break;
		case OP_PB_TOGGLE_DLALL:
			auto_download = !auto_download;
			break;
		case OP_HARDQUIT:
		case OP_QUIT:
			if (ctrl->downloads_in_progress() > 0) {
				dllist_form.set("msg", _("Error: can't quit: download(s) in progress."));
				update_view = true;
			} else {
				quit = true;
			}
			break;
		case OP_PB_MOREDL:
			ctrl->increase_parallel_downloads();
			break;
		case OP_PB_LESSDL:
			ctrl->decrease_parallel_downloads();
			break;
		case OP_PB_DOWNLOAD: {
			if (ctrl->downloads().size() >= 1) {
				const auto idx = downloads_list.get_position();
				auto& item = ctrl->downloads()[idx];
				if (item.status() != DlStatus::DOWNLOADING) {
					ctrl->start_download(item);
				}
			}
		}
		break;
		case OP_PB_PLAY: {
			if (ctrl->downloads().size() >= 1) {
				const auto idx = downloads_list.get_position();
				DlStatus status =
					ctrl->downloads()[idx].status();
				if (status == DlStatus::FINISHED ||
					status == DlStatus::PLAYED ||
					status == DlStatus::READY) {
					ctrl->play_file(ctrl->downloads()[idx]
						.filename());
					ctrl->downloads()[idx].set_status(
						DlStatus::PLAYED);
				} else {
					dllist_form.set("msg",
						_("Error: download needs to be "
							"finished before the file "
							"can be played."));
				}
			}
		}
		break;
		case OP_PB_MARK_FINISHED: {
			auto& downloads = ctrl->downloads();
			if (downloads.size() >= 1) {
				const auto idx = downloads_list.get_position();
				DlStatus status =
					downloads[idx].status();
				if (status == DlStatus::PLAYED) {
					downloads[idx].set_status(DlStatus::FINISHED);
					if (idx + 1 < downloads.size()) {
						downloads_list.set_position(idx + 1);
					}
				}
			}
		}
		break;
		case OP_PB_CANCEL: {
			if (ctrl->downloads().size() >= 1) {
				const auto idx = downloads_list.get_position();
				if (ctrl->downloads()[idx].status() ==
					DlStatus::DOWNLOADING) {
					ctrl->downloads()[idx].set_status(
						DlStatus::CANCELLED);
				}
			}
		}
		break;
		case OP_PB_DELETE: {
			auto& downloads = ctrl->downloads();
			if (downloads.size() >= 1) {
				const auto idx = downloads_list.get_position();
				if (downloads[idx].status() !=
					DlStatus::DOWNLOADING) {
					downloads[idx].set_status(DlStatus::DELETED);
					if (idx + 1 < downloads.size()) {
						downloads_list.set_position(idx + 1);
					}
				}
			}
		}
		break;
		case OP_PB_PURGE:
			if (ctrl->downloads_in_progress() > 0) {
				dllist_form.set("msg",
					_("Error: unable to perform operation: "
						"download(s) in progress."));
			} else {
				ctrl->purge_queue();
			}
			update_view = true;
			break;
		case OP_HELP:
			run_help();
			break;
		default:
			break;
		}

	} while (!quit);
}

void PbView::handle_resize()
{
	std::vector<std::reference_wrapper<newsboat::Stfl::Form>> forms = {dllist_form, help_form};
	for (const auto& form : forms) {
		form.get().run(-3);
	}
	update_view = true;
}

void PbView::apply_colors_to_all_forms()
{
	using namespace std::placeholders;
	colorman.apply_colors(std::bind(&newsboat::Stfl::Form::set, &dllist_form, _1,
			_2));
	colorman.apply_colors(std::bind(&newsboat::Stfl::Form::set, &help_form, _1,
			_2));
}

std::pair<double, std::string> PbView::get_speed_human_readable(double kbps)
{
	if (kbps < 1024) {
		return std::make_pair(kbps, _("KB/s"));
	} else if (kbps < 1024 * 1024) {
		return std::make_pair(kbps / 1024, _("MB/s"));
	} else {
		return std::make_pair(kbps / 1024 / 1024, _("GB/s"));
	}
}

void PbView::run_help()
{
	set_help_keymap_hint();

	help_form.set("head", _("Help"));

	const auto descs = keys->get_keymap_descriptions("podboat");

	ListFormatter listfmt;

	for (const auto& desc : descs) {
		const std::string descline = strprintf::fmt("%-7s %-23s %s",
				desc.key,
				desc.cmd,
				desc.desc);

		listfmt.add_line(descline);
	}

	help_textview.stfl_replace_lines(listfmt.get_lines_count(),
		listfmt.format_list());

	bool quit = false;

	do {
		const char* event = help_form.run(0);
		if (!event) {
			continue;
		}

		if (strcmp(event, "RESIZE") == 0) {
			handle_resize();
			continue;
		}

		Operation op = keys->get_operation(event, "help");

		switch (op) {
		case OP_SK_UP:
			help_textview.scroll_up();
			break;
		case OP_SK_DOWN:
			help_textview.scroll_down();
			break;
		case OP_SK_HOME:
			help_textview.scroll_to_top();
			break;
		case OP_SK_END:
			help_textview.scroll_to_bottom();
			break;
		case OP_SK_PGUP:
			help_textview.scroll_page_up();
			break;
		case OP_SK_PGDOWN:
			help_textview.scroll_page_down();
			break;
		case OP_HARDQUIT:
		case OP_QUIT:
			quit = true;
			break;
		default:
			break;
		}
	} while (!quit);
}

std::string PbView::prepare_keymaphint(KeyMapHintEntry* hints)
{
	std::string keymap_hint;
	for (int i = 0; hints[i].op != OP_NIL; ++i) {
		std::string bound_keys = utils::join(keys->get_keys(hints[i].op, "podboat"),
				",");
		if (bound_keys.empty()) {
			bound_keys = "<none>";
		}
		keymap_hint.append(bound_keys);
		keymap_hint.append(":");
		keymap_hint.append(hints[i].text);
		keymap_hint.append(" ");
	}
	return keymap_hint;
}

void PbView::set_help_keymap_hint()
{
	static KeyMapHintEntry hints[] = {{OP_QUIT, _("Quit")}, {OP_NIL, nullptr}};
	std::string keymap_hint = prepare_keymaphint(hints);
	help_form.set("help", keymap_hint);
}

void PbView::set_dllist_keymap_hint()
{
	static KeyMapHintEntry hints[] = {{OP_QUIT, _("Quit")},
		{OP_PB_DOWNLOAD, _("Download")},
		{OP_PB_CANCEL, _("Cancel")},
		{OP_PB_DELETE, _("Delete")},
		{OP_PB_PURGE, _("Purge Finished")},
		{OP_PB_TOGGLE_DLALL, _("Toggle Automatic Download")},
		{OP_PB_PLAY, _("Play")},
		{OP_PB_MARK_FINISHED, _("Mark as Finished")},
		{OP_HELP, _("Help")},
		{OP_NIL, nullptr}
	};

	std::string keymap_hint = prepare_keymaphint(hints);
	dllist_form.set("help", keymap_hint);
}

std::string PbView::format_line(const std::string& podlist_format,
	const Download& dl,
	unsigned int pos,
	unsigned int width)
{
	FmtStrFormatter fmt;

	const double speed_kbps = dl.kbps();
	const auto speed = get_speed_human_readable(speed_kbps);

	fmt.register_fmt('i', strprintf::fmt("%u", pos + 1));
	fmt.register_fmt('d',
		strprintf::fmt("%.1f", dl.current_size() / (1024 * 1024)));
	fmt.register_fmt(
		't', strprintf::fmt("%.1f", dl.total_size() / (1024 * 1024)));
	fmt.register_fmt('p', strprintf::fmt("%.1f", dl.percents_finished()));
	fmt.register_fmt('k', strprintf::fmt("%.2f", speed_kbps));
	fmt.register_fmt('K', strprintf::fmt("%.2f %s", speed.first, speed.second));
	fmt.register_fmt('S', strprintf::fmt("%s", dl.status_text()));
	fmt.register_fmt('u', strprintf::fmt("%s", dl.url()));
	fmt.register_fmt('F', strprintf::fmt("%s", dl.filename()));
	fmt.register_fmt('b', strprintf::fmt("%s", dl.basename()));

	auto formattedLine = fmt.do_format(podlist_format, width);
	formattedLine = utils::quote_for_stfl(formattedLine);
	return formattedLine;
}

} // namespace podboat
<|endoftext|>


<commit_before>#include "player.h"

Pacman::Pacman()
{
	MobileObject::MobileObject();
	x = 0;
	y = 0;
	boundX = 0;
	boundY = 0;
	velocity = 1;

	image = NULL;
};

void Pacman::Init(float x, float y, int boundX,  int boundY, int velocity, float lives, ALLEGRO_BITMAP *image)
{
	MobileObject::Init(x, y, boundX, boundY, image);

	Pacman::velocity = velocity;
	Pacman::lives = lives;

	maxFrame = 6;
	curFrame = 0;
	frameCount = 0;								//depends on sprite NEED TO BE FILLED WITH CORRECT VALUES
	frameDelay = 3;
	frameWidth = 32;
	frameHeight = 32;
	animationColumns = 6;

	//that makes the Pacman rotating; I don't know if this can be done fancier
	angle = 0;

	Pacman::image = image;
	Pacman::SetDir(1);
}

void Pacman::Movement(int keys)
{
	if(keys == UP)
		{
			MobileObject::MoveUp();
			angle = -ALLEGRO_PI / 2;
		}
	else if(keys == DOWN)
		{
			MobileObject::MoveDown();
			angle = ALLEGRO_PI / 2;
		}
	else if(keys == LEFT)
		{
			MobileObject::MoveLeft();
			angle = ALLEGRO_PI;
		}
	else if(keys == RIGHT)
		{
			MobileObject::MoveRight();
			angle = 0;
		}
}

void Pacman::Destroy()
{
	MobileObject::Destroy();

}
void Pacman::Update(int keys)
{
	Pacman::Movement(direction);
	if((direction != keys) && !((int)x % 32) && !((int)y % 32))
	{
		direction = keys;
		Pacman::Movement(keys);
	}

	if(++frameCount >= frameDelay)
	{
		curFrame ++;
		if(curFrame >= maxFrame)
			curFrame = 0;
		else if(curFrame <= 0)
			curFrame = maxFrame;

		frameCount = 0;
	}
	if(Pacman::x < 0)
		Pacman::x = WIDTH + 31;
	else if(Pacman::x > WIDTH+32)
		Pacman::x = 1;
	if(Pacman::y < 0)
		Pacman::y = HEIGHT + 31;
	else if (Pacman::y > HEIGHT+32)
		Pacman::y = 1;
	// Now it's smooth and silky
}
void Pacman::Render()
{

	MobileObject::Render();

	int fx = (curFrame % animationColumns) * frameWidth;
	int fy = (curFrame / animationColumns) * frameHeight;

		al_draw_tinted_scaled_rotated_bitmap_region(image, fx, fy, frameWidth, frameHeight,
		al_map_rgba_f(1, 1, 1, 1.0), frameWidth / 2, frameHeight / 2, x - frameWidth / 2,
		y - frameHeight / 2, 1, 1, angle, 0);

}

void Pacman::Collided(int ObjectID)
{

}<commit_msg>Little fix regarding the teleport<commit_after>#include "player.h"

Pacman::Pacman()
{
	MobileObject::MobileObject();
	x = 0;
	y = 0;
	boundX = 0;
	boundY = 0;
	velocity = 1;

	image = NULL;
};

void Pacman::Init(float x, float y, int boundX,  int boundY, int velocity, float lives, ALLEGRO_BITMAP *image)
{
	MobileObject::Init(x, y, boundX, boundY, image);

	Pacman::velocity = velocity;
	Pacman::lives = lives;

	maxFrame = 6;
	curFrame = 0;
	frameCount = 0;								//depends on sprite NEED TO BE FILLED WITH CORRECT VALUES
	frameDelay = 3;
	frameWidth = 32;
	frameHeight = 32;
	animationColumns = 6;

	//that makes the Pacman rotating; I don't know if this can be done fancier
	angle = 0;

	Pacman::image = image;
	Pacman::SetDir(1);
}

void Pacman::Movement(int keys)
{
	if(keys == UP)
		{
			MobileObject::MoveUp();
			angle = -ALLEGRO_PI / 2;
		}
	else if(keys == DOWN)
		{
			MobileObject::MoveDown();
			angle = ALLEGRO_PI / 2;
		}
	else if(keys == LEFT)
		{
			MobileObject::MoveLeft();
			angle = ALLEGRO_PI;
		}
	else if(keys == RIGHT)
		{
			MobileObject::MoveRight();
			angle = 0;
		}
}

void Pacman::Destroy()
{
	MobileObject::Destroy();

}
void Pacman::Update(int keys)
{
	Pacman::Movement(direction);
	if((direction != keys) && !((int)x % 32) && !((int)y % 32))
	{
		direction = keys;
		Pacman::Movement(keys);
	}

	if(++frameCount >= frameDelay)
	{
		curFrame ++;
		if(curFrame >= maxFrame)
			curFrame = 0;
		else if(curFrame <= 0)
			curFrame = maxFrame;

		frameCount = 0;
	}
	if(Pacman::x < 0)
		Pacman::x = WIDTH + 32;
	else if(Pacman::x > WIDTH+32)
		Pacman::x = 1;
	if(Pacman::y < 0)
		Pacman::y = HEIGHT + 32;
	else if (Pacman::y > HEIGHT+32)
		Pacman::y = 1;
	// Now it's smooth and silky
}
void Pacman::Render()
{

	MobileObject::Render();

	int fx = (curFrame % animationColumns) * frameWidth;
	int fy = (curFrame / animationColumns) * frameHeight;

		al_draw_tinted_scaled_rotated_bitmap_region(image, fx, fy, frameWidth, frameHeight,
		al_map_rgba_f(1, 1, 1, 1.0), frameWidth / 2, frameHeight / 2, x - frameWidth / 2,
		y - frameHeight / 2, 1, 1, angle, 0);

}

void Pacman::Collided(int ObjectID)
{

}<|endoftext|>


<commit_before>/*

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

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

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

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

*/

#include <iostream>

#include "libtorrent/policy.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/peer_connection.hpp"

namespace
{
	enum
	{
		// we try to maintain 4 requested blocks in the download
		// queue
		request_queue = 16
	};

	using namespace libtorrent;

	// TODO: replace these two functions with std::find_first_of
	template<class It1, class It2>
	bool has_intersection(It1 start1, It1 end1, It2 start2, It2 end2)
	{
		for (;start1 != end1; ++start1)
			for (;start2 != end2; ++start2)
				if (*start1 == *start2) return true;
		return false;
	}

	piece_block find_first_common(const std::vector<piece_block>& queue,
		const std::vector<piece_block>& busy)
	{
		for (std::vector<piece_block>::const_reverse_iterator i
			= queue.rbegin();
			i != queue.rend();
			++i)
		{
			for (std::vector<piece_block>::const_iterator j
				= busy.begin();
				j != busy.end();
				++j)
			{
				if ((*j) == (*i)) return *i;
			}
		}
		assert(false);
	}

	void request_a_block(torrent& t, peer_connection& c)
	{
		int num_requests = request_queue - c.download_queue().size();

		// if our request queue is already full, we
		// don't have to make any new requests yet
		if (num_requests <= 0) return;

		piece_picker& p = t.picker();
		std::vector<piece_block> interesting_pieces;
		interesting_pieces.reserve(100);

		// picks the interesting pieces from this peer
		// the integer is the number of pieces that
		// should be guaranteed to be available for download
		// (if this number is too big, too many pieces are
		// picked and cpu-time is wasted)
		p.pick_pieces(c.get_bitfield(), interesting_pieces, num_requests);

		// this vector is filled with the interestin pieces
		// that some other peer is currently downloading
		// we should then compare this peer's download speed
		// with the other's, to see if we should abort another
		// peer_connection in favour of this one
		std::vector<piece_block> busy_pieces;
		busy_pieces.reserve(10);

		for (std::vector<piece_block>::iterator i = interesting_pieces.begin();
			i != interesting_pieces.end();
			++i)
		{
			if (p.is_downloading(*i))
			{
				busy_pieces.push_back(*i);
				continue;
			}

			// ok, we found a piece that's not being downloaded
			// by somebody else. request it from this peer
			c.request_block(*i);
			num_requests--;
			if (num_requests <= 0) return;
		}

		if (busy_pieces.empty()) return;

		// first look for blocks that are just queued
		// and not actually sent to us yet
		// (then we can cancel those and request them
		// from this peer instead)

		peer_connection* peer = 0;
		float down_speed = 0.f;
		// find the peer with the lowest download
		// speed that also has a piece thatt this
		// peer could send us
		for (torrent::peer_iterator i = t.begin();
			i != t.end();
			++i)
		{
			const std::vector<piece_block>& queue = (*i)->download_queue();
			if ((*i)->statistics().down_peak() > down_speed
				&& has_intersection(busy_pieces.begin(),
					busy_pieces.end(),
					queue.begin(),
					queue.end()))
			{
				peer = *i;
				down_speed = (*i)->statistics().down_peak();
			}
		}

		assert(peer != 0);

		// this peer doesn't have a faster connection than the
		// slowest peer. Don't take over any blocks
		if (c.statistics().down_peak() <= down_speed) return;

		// find a suitable block to take over from this peer
		piece_block block = find_first_common(peer->download_queue(), busy_pieces);
		peer->cancel_block(block);
		c.request_block(block);

		// the one we interrupted may need to request a new piece
		request_a_block(t, *peer);

		num_requests--;
	}
}

namespace libtorrent
{
/*
	TODO: make two proxy classes that filter out
	all unneccesary members from torrent and peer_connection
	to make it easier to use them in the policy

	useful member functions:

	void torrent::connect_to_peer(address, peer_id);
	piece_picker& torrent::picker();
	std::vector<peer_connection*>::const_iterator torrent::begin() const
	std::vector<peer_connection*>::const_iterator torrent::end() const

	void peer_connection::interested();
	void peer_connection::not_interested();
	void peer_connection::choke();
	void peer_connection::unchoke();
	void peer_connection::request_piece(int index);
	const std::vector<int>& peer_connection::download_queue();
*/

	policy::policy(torrent* t)
		: m_num_peers(0)
		, m_torrent(t)
	{}

	// this is called when a connection is made, before any
	// handshake (it's possible to ban certain ip:s).
	bool policy::accept_connection(const address& remote)
	{
		m_num_peers++;
		return true;
	}

	void policy::peer_from_tracker(const address& remote, const peer_id& id)
	{
		try
		{
			m_torrent->connect_to_peer(remote, id);
			m_num_peers++;
		}
		catch(network_error&) {}
	}

	// this is called when we are choked by a peer
	// i.e. a peer lets us know that we will not receive
	// anything for a while
	void policy::choked(peer_connection& c)
	{
		c.choke();
	}

	void policy::piece_finished(peer_connection& c, int index, bool successfully_verified)
	{
		// TODO: if verification failed, mark the peers that were involved
		// in some way
	}

	void policy::block_finished(peer_connection& c, piece_block b)
	{
		if (c.has_peer_choked()) return;
		request_a_block(*m_torrent, c);
	}

	// this is called when we are unchoked by a peer
	// i.e. a peer lets us know that we will receive
	// data from now on
	void policy::unchoked(peer_connection& c)
	{
		c.unchoke();
		if (c.is_interesting()) request_a_block(*m_torrent, c);
	}

	void policy::interested(peer_connection& c)
	{
		c.unchoke();
	}

	void policy::not_interested(peer_connection& c)
	{
	}

	void policy::connection_closed(const peer_connection& c)
	{
	}

	void policy::peer_is_interesting(peer_connection& c)
	{
		c.interested();
		if (c.has_peer_choked()) return;
		request_a_block(*m_torrent, c);
	}
}
<commit_msg>bugfix<commit_after>/*

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

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

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

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

*/

#include <iostream>

#include "libtorrent/policy.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/peer_connection.hpp"

namespace
{
	enum
	{
		// we try to maintain 4 requested blocks in the download
		// queue
		request_queue = 16
	};

	using namespace libtorrent;

	// TODO: replace these two functions with std::find_first_of
	template<class It1, class It2>
	bool has_intersection(It1 start1, It1 end1, It2 start2, It2 end2)
	{
		for (;start1 != end1; ++start1)
			for (;start2 != end2; ++start2)
				if (*start1 == *start2) return true;
		return false;
	}

	piece_block find_first_common(const std::vector<piece_block>& queue,
		const std::vector<piece_block>& busy)
	{
		for (std::vector<piece_block>::const_reverse_iterator i
			= queue.rbegin();
			i != queue.rend();
			++i)
		{
			for (std::vector<piece_block>::const_iterator j
				= busy.begin();
				j != busy.end();
				++j)
			{
				if ((*j) == (*i)) return *i;
			}
		}
		assert(false);
	}

	void request_a_block(torrent& t, peer_connection& c)
	{
		int num_requests = request_queue - c.download_queue().size();

		// if our request queue is already full, we
		// don't have to make any new requests yet
		if (num_requests <= 0) return;

		piece_picker& p = t.picker();
		std::vector<piece_block> interesting_pieces;
		interesting_pieces.reserve(100);

		// picks the interesting pieces from this peer
		// the integer is the number of pieces that
		// should be guaranteed to be available for download
		// (if this number is too big, too many pieces are
		// picked and cpu-time is wasted)
		p.pick_pieces(c.get_bitfield(), interesting_pieces, num_requests);

		// this vector is filled with the interestin pieces
		// that some other peer is currently downloading
		// we should then compare this peer's download speed
		// with the other's, to see if we should abort another
		// peer_connection in favour of this one
		std::vector<piece_block> busy_pieces;
		busy_pieces.reserve(10);

		for (std::vector<piece_block>::iterator i = interesting_pieces.begin();
			i != interesting_pieces.end();
			++i)
		{
			if (p.is_downloading(*i))
			{
				busy_pieces.push_back(*i);
				continue;
			}

			// ok, we found a piece that's not being downloaded
			// by somebody else. request it from this peer
			c.request_block(*i);
			num_requests--;
			if (num_requests <= 0) return;
		}

		if (busy_pieces.empty()) return;

		// first look for blocks that are just queued
		// and not actually sent to us yet
		// (then we can cancel those and request them
		// from this peer instead)

		peer_connection* peer = 0;
		float down_speed = -1.f;
		// find the peer with the lowest download
		// speed that also has a piece thatt this
		// peer could send us
		for (torrent::peer_iterator i = t.begin();
			i != t.end();
			++i)
		{
			const std::vector<piece_block>& queue = (*i)->download_queue();
			if ((*i)->statistics().down_peak() > down_speed
				&& has_intersection(busy_pieces.begin(),
					busy_pieces.end(),
					queue.begin(),
					queue.end()))
			{
				peer = *i;
				down_speed = (*i)->statistics().down_peak();
			}
		}

		assert(peer != 0);

		// this peer doesn't have a faster connection than the
		// slowest peer. Don't take over any blocks
		if (c.statistics().down_peak() <= down_speed) return;

		// find a suitable block to take over from this peer
		piece_block block = find_first_common(peer->download_queue(), busy_pieces);
		peer->cancel_block(block);
		c.request_block(block);

		// the one we interrupted may need to request a new piece
		request_a_block(t, *peer);

		num_requests--;
	}
}

namespace libtorrent
{
/*
	TODO: make two proxy classes that filter out
	all unneccesary members from torrent and peer_connection
	to make it easier to use them in the policy

	useful member functions:

	void torrent::connect_to_peer(address, peer_id);
	piece_picker& torrent::picker();
	std::vector<peer_connection*>::const_iterator torrent::begin() const
	std::vector<peer_connection*>::const_iterator torrent::end() const

	void peer_connection::interested();
	void peer_connection::not_interested();
	void peer_connection::choke();
	void peer_connection::unchoke();
	void peer_connection::request_piece(int index);
	const std::vector<int>& peer_connection::download_queue();
*/

	policy::policy(torrent* t)
		: m_num_peers(0)
		, m_torrent(t)
	{}

	// this is called when a connection is made, before any
	// handshake (it's possible to ban certain ip:s).
	bool policy::accept_connection(const address& remote)
	{
		m_num_peers++;
		return true;
	}

	void policy::peer_from_tracker(const address& remote, const peer_id& id)
	{
		try
		{
			m_torrent->connect_to_peer(remote, id);
			m_num_peers++;
		}
		catch(network_error&) {}
	}

	// this is called when we are choked by a peer
	// i.e. a peer lets us know that we will not receive
	// anything for a while
	void policy::choked(peer_connection& c)
	{
		c.choke();
	}

	void policy::piece_finished(peer_connection& c, int index, bool successfully_verified)
	{
		// TODO: if verification failed, mark the peers that were involved
		// in some way
	}

	void policy::block_finished(peer_connection& c, piece_block b)
	{
		if (c.has_peer_choked()) return;
		request_a_block(*m_torrent, c);
	}

	// this is called when we are unchoked by a peer
	// i.e. a peer lets us know that we will receive
	// data from now on
	void policy::unchoked(peer_connection& c)
	{
		c.unchoke();
		if (c.is_interesting()) request_a_block(*m_torrent, c);
	}

	void policy::interested(peer_connection& c)
	{
		c.unchoke();
	}

	void policy::not_interested(peer_connection& c)
	{
	}

	void policy::connection_closed(const peer_connection& c)
	{
	}

	void policy::peer_is_interesting(peer_connection& c)
	{
		c.interested();
		if (c.has_peer_choked()) return;
		request_a_block(*m_torrent, c);
	}
}
<|endoftext|>


<commit_before>
#include "reader.h"

#include <cassert>
#include <cstring>
#include <stack>

#define BUFF_CAP 4096
#define MAX_SEQ 524288

using std::istream;
using std::stack;

namespace AMOS {

  Reader::Reader(istream& input): input(&input), buff_written(0) {
    buff = new char[BUFF_CAP];
    buff_cap = BUFF_CAP;
    states.push(OUT);
  }

  bool Reader::has_next() {
    if (buff_written == 0) {
      return buffer_next() > 0;
    }

    return buff_written > 0;
  }

  int Reader::skip_next() {
    int skipped = 0;

    if (buff_written == 0) {
      skipped = buffer_next();
      if (skipped == -1) {
        return -1;
      }
    } else {
      skipped = buff_written;
    }

    //cerr << "SKIP " << buff << endl;
    buffer_clear();

    return skipped;
  }

  ObjectType Reader::next_type() {
    return next_type_;
  }

  class Read* Reader::next_read() {
    //cerr << "NEXT_READ" << endl;
    if (!has_next()) {
      return nullptr;
    }

    while (next_type() != ObjectType::Read) {
      //cerr << "WRONG TYPE" << endl;
      skip_next();
      if (!has_next()) {
        return nullptr;
      }
    }

    //cout << "READ " << buff << endl;
    skip_next();
    // add code for parsing read

    return nullptr;
  }

  int Reader::buffer_clear() {
    //cerr << "FLUSH " << buff << endl;
    int was_written = buff_written;
    buff_written = 0;
    buff_marks.clear();
    return was_written;
  }

  int Reader::buffer_double() {
    buff = (char *) realloc(buff, buff_cap * 2);
    if (buff == nullptr) {
      buff_cap = 0;
      buff_written = 0;
      return -1;
    }

    buff_cap *= 2;
    return buff_cap;
  }

  int Reader::buffer_next() {
    assert(states.size() == 1);
    assert(buff_written == 0);

    if (input->eof()) return 0;

    while (true) {
      auto line = buff + buff_written;

      input->getline(line, buff_cap - buff_written);

      int line_start = buff_written;
      buff_written += strlen(line);

      if (input->eof()) {
        return -1;
      }
      if (input->fail()) {
        return -1;
      }

      int seq_start = 0;
      auto state = states.top();
      switch (state) {
        case OUT:
          if (strncmp(line, "{RED", 4) == 0) {
            states.push(IN);
            next_type_ = ObjectType::Read;
          } else if (strncmp(line, "{OVL", 4) == 0) {
            states.push(IN);
            next_type_ = ObjectType::Overlap;
          } else if (strncmp(line, "{UNV", 4) == 0) {
            states.push(IN);
            next_type_ = ObjectType::Universal;
          } else if (strncmp(line, "{LIB", 4) == 0) {
            states.push(IN);
            next_type_ = ObjectType::Library;
          } else if (strncmp(line, "{FRG", 4) == 0) {
            states.push(IN);
            next_type_ = ObjectType::Fragment;
          } else {
            assert(false);
          }

          buff_marks.push_back(BufferMark(ObjectDef, line_start, buff_written));
          break;
        case IN:
          if (line[0] == '}') {
            states.pop();
          } else if (strncmp(line, "seq:", 4) == 0) {
            states.push(IN_SEQ);
            seq_start = line_start;
          } else if (strncmp(line, "qlt:", 4) == 0) {
            states.push(IN_QLT);
            seq_start = line_start;
          } else if (strncmp(line, "com:", 4) == 0) {
            states.push(IN_COM);
            seq_start = line_start;
          } else if (strncmp(line, "{DST", 4) == 0) {
            buff_marks.push_back(BufferMark(ObjectDef, line_start, buff_written));
            states.push(IN);
          } else {
            buff_marks.push_back(BufferMark(AttrDef, line_start, buff_written));
          }
          break;
        case IN_SEQ:
        case IN_QLT:
        case IN_COM:
          if (line[0] == '.') {
            buff_marks.push_back(BufferMark(ObjectDef, seq_start, buff_written));
            states.pop();
          }
          break;
        default:
          assert(false);
      }

      if (states.size() == 1) {
        //cerr << "FILL " << buff << endl;
        return buff_written;
      }
    }

    return -1;
  }

  //int get_reads(std::vector<const Read*>& container, FILE *fd) {
    //int records = 0;

    //char line[buff_cap] = {0};

    //ReaderState state = OUT;
    //Read* curr_read = new Read();
    //char curr_seq[MAX_SEQ] = {0};
    //int curr_seq_len = 0;
    //int line_len = 0;
    //long last_pos = ftell(fd);
    //const char **dst_str = nullptr;
    //while (!feof(fd)) {
      //// read next line and update pointers
      //fgets(line, buff_cap, fd);
      //long curr_pos = ftell(fd);
      //assert(curr_pos - last_pos < buff_cap);
      //line_len = curr_pos - last_pos;
      //last_pos = curr_pos;

      //// strip \n
      //line[line_len - 1] = 0;
      //line_len--;

      //switch (state) {
        //case OUT:
          //if (strstr(line, "{RED") != nullptr) {
            //state = IN_READ;
          //}
          //break;
        //case IN_READ:
          //if (sscanf(line, " iid: %d ", &curr_read->iid)) {
            //state = IN_READ;
          //} else if (strstr(line, "seq:") != nullptr) {
            //dst_str = &(curr_read->seq);
            //state = IN_SEQ;
          //} else if (strstr(line, "qlt:") != nullptr) {
            //dst_str = &(curr_read->qlt);
            //state = IN_QLT;
          //} else if (sscanf(line, " clr: %d, %d ", &curr_read->clr_lo, &curr_read->clr_hi)) {
            //state = IN_READ;
          //} else if (line[0] == '}') {
            //state = OUT;
            //container.push_back(curr_read);
            //curr_read = new Read();
            //records++;
          //}
          //break;
        //case IN_SEQ:
        //case IN_QLT:
          //if (line[0] == '.') {
            //assert(dst_str != nullptr);
            //char *cpy = new char[curr_seq_len + 1];
            //strncpy(cpy, curr_seq, curr_seq_len + 1);
            //curr_seq_len = 0;
            //*dst_str = cpy; // assign copied string to the destination
            //dst_str = nullptr;
            //state = IN_READ;
          //} else {
            //assert(line_len < MAX_SEQ - curr_seq_len);
            //strcpy(curr_seq + curr_seq_len, line);
            //curr_seq_len += line_len;
          //}
          //break;
        //default:
          //assert(false);
      //}
    //}
    //delete curr_read;

    //return records;
  //}

  //int get_overlaps(std::vector<const Overlap*>& container, FILE* fd) {
    //int records = 0;

    //char line[buff_cap] = {0};

    //ReaderState state = OUT;
    //Overlap* curr_overlap = new Overlap();
    //int line_len = 0;
    //long last_pos = ftell(fd);
    //const char **dst_str = nullptr;
    //while (!feof(fd)) {
      //// read next line and update pointers
      //fgets(line, buff_cap, fd);
      //long curr_pos = ftell(fd);
      //assert(curr_pos - last_pos < buff_cap);
      //line_len = curr_pos - last_pos;
      //last_pos = curr_pos;

      //// strip \n
      //line[line_len - 1] = 0;
      //line_len--;

      //switch (state) {
        //case OUT:
          //if (strstr(line, "{OVL") != nullptr) {
            //state = IN_OVL;
          //}
          //break;
        //case IN_OVL:
          //if (sscanf(line, " rds: %d, %d ", &curr_overlap->read1, &curr_overlap->read2)) {
            //state = IN_OVL;
          //} else if (sscanf(line, " adj: %c", &curr_overlap->adjacency)) {
            //state = IN_OVL;
          //} else if (sscanf(line, " ahg: %d", &curr_overlap->a_hang)) {
            //state = IN_OVL;
          //} else if (sscanf(line, " bhg: %d", &curr_overlap->b_hang)) {
            //state = IN_OVL;
          //} else if (sscanf(line, " scr: %d", &curr_overlap->score)) {
            //state = IN_OVL;
          //} else if (line[0] == '}') {
            //state = OUT;
            //container.push_back(curr_overlap);
            //curr_overlap = new Overlap();
            //records++;
          //}
          //break;
        //default:
          //assert(false);
      //}
    //}
    //delete curr_overlap;

    //return records;
  //}
}
<commit_msg>remove commented out code<commit_after>
#include "reader.h"

#include <cassert>
#include <cstring>
#include <stack>

#define BUFF_CAP 4096
#define MAX_SEQ 524288

using std::istream;
using std::stack;

namespace AMOS {

  Reader::Reader(istream& input): input(&input), buff_written(0) {
    buff = new char[BUFF_CAP];
    buff_cap = BUFF_CAP;
    states.push(OUT);
  }

  bool Reader::has_next() {
    if (buff_written == 0) {
      return buffer_next() > 0;
    }

    return buff_written > 0;
  }

  int Reader::skip_next() {
    int skipped = 0;

    if (buff_written == 0) {
      skipped = buffer_next();
      if (skipped == -1) {
        return -1;
      }
    } else {
      skipped = buff_written;
    }

    //cerr << "SKIP " << buff << endl;
    buffer_clear();

    return skipped;
  }

  ObjectType Reader::next_type() {
    return next_type_;
  }

  class Read* Reader::next_read() {
    //cerr << "NEXT_READ" << endl;
    if (!has_next()) {
      return nullptr;
    }

    while (next_type() != ObjectType::Read) {
      //cerr << "WRONG TYPE" << endl;
      skip_next();
      if (!has_next()) {
        return nullptr;
      }
    }

    //cout << "READ " << buff << endl;
    skip_next();
    // add code for parsing read

    return nullptr;
  }

  int Reader::buffer_clear() {
    //cerr << "FLUSH " << buff << endl;
    int was_written = buff_written;
    buff_written = 0;
    buff_marks.clear();
    return was_written;
  }

  int Reader::buffer_double() {
    buff = (char *) realloc(buff, buff_cap * 2);
    if (buff == nullptr) {
      buff_cap = 0;
      buff_written = 0;
      return -1;
    }

    buff_cap *= 2;
    return buff_cap;
  }

  int Reader::buffer_next() {
    assert(states.size() == 1);
    assert(buff_written == 0);

    if (input->eof()) return 0;

    while (true) {
      auto line = buff + buff_written;

      input->getline(line, buff_cap - buff_written);

      int line_start = buff_written;
      buff_written += strlen(line);

      if (input->eof()) {
        return -1;
      }
      if (input->fail()) {
        return -1;
      }

      int seq_start = 0;
      auto state = states.top();
      switch (state) {
        case OUT:
          if (strncmp(line, "{RED", 4) == 0) {
            states.push(IN);
            next_type_ = ObjectType::Read;
          } else if (strncmp(line, "{OVL", 4) == 0) {
            states.push(IN);
            next_type_ = ObjectType::Overlap;
          } else if (strncmp(line, "{UNV", 4) == 0) {
            states.push(IN);
            next_type_ = ObjectType::Universal;
          } else if (strncmp(line, "{LIB", 4) == 0) {
            states.push(IN);
            next_type_ = ObjectType::Library;
          } else if (strncmp(line, "{FRG", 4) == 0) {
            states.push(IN);
            next_type_ = ObjectType::Fragment;
          } else {
            assert(false);
          }

          buff_marks.push_back(BufferMark(ObjectDef, line_start, buff_written));
          break;
        case IN:
          if (line[0] == '}') {
            states.pop();
          } else if (strncmp(line, "seq:", 4) == 0) {
            states.push(IN_SEQ);
            seq_start = line_start;
          } else if (strncmp(line, "qlt:", 4) == 0) {
            states.push(IN_QLT);
            seq_start = line_start;
          } else if (strncmp(line, "com:", 4) == 0) {
            states.push(IN_COM);
            seq_start = line_start;
          } else if (strncmp(line, "{DST", 4) == 0) {
            buff_marks.push_back(BufferMark(ObjectDef, line_start, buff_written));
            states.push(IN);
          } else {
            buff_marks.push_back(BufferMark(AttrDef, line_start, buff_written));
          }
          break;
        case IN_SEQ:
        case IN_QLT:
        case IN_COM:
          if (line[0] == '.') {
            buff_marks.push_back(BufferMark(ObjectDef, seq_start, buff_written));
            states.pop();
          }
          break;
        default:
          assert(false);
      }

      if (states.size() == 1) {
        //cerr << "FILL " << buff << endl;
        return buff_written;
      }
    }

    return -1;
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- interface include --------------------------------------------------------
#include "MT_Storage.h"

//--- standard modules used ----------------------------------------------------
#include "Threads.h"
#include "PoolAllocator.h"
#include "SysLog.h"
#include "Dbg.h"

//--- c-library modules used ---------------------------------------------------
#if !defined(WIN32)
#include <stdlib.h>
#endif

THREADKEY MT_Storage::fgAllocatorKey = 0;

#define FindAllocator(wdallocator)									\
		GETTLSDATA(MT_Storage::fgAllocatorKey, wdallocator, Allocator)

void TLSDestructor(void *)
{
	// destructor function for thread local storage
}

static Mutex *gsAllocatorInit = 0;		// protect all data structures used by MT_Storage

#if 0
#define TrackLockerInit(lockvar) , lockvar(0)
#define TrackLockerDef(lockvar)	volatile long lockvar

class EXPORTDECL_MTFOUNDATION CurrLockerEntry
{
	volatile long &frLockerId;
public:
	CurrLockerEntry(volatile long &rLockerId, const char *pFile, long lLine)
		: frLockerId(rLockerId) {
		CheckException(pFile, lLine);
		frLockerId = Thread::MyId();
	}
	~CurrLockerEntry() {
		frLockerId = 0;
	}
	inline void CheckException(const char *pFile, long lLine) {
		if ( frLockerId != 0 ) {
			long lOther = frLockerId;
			char buf[256];
			snprintf(buf, sizeof(buf), "\n%s:%d Another Locker entered already! otherThreadId:%d currentThreadId:%d\n", pFile, lLine, lOther, Thread::MyId());
			SysLog::WriteToStderr(buf, strlen(buf));
		}
	}
};

#define TrackLocker(lockvar)	CurrLockerEntry aEntry(lockvar, __FILE__, __LINE__)

#else

#define TrackLockerInit(lockvar)
#define TrackLockerDef(lockvar)
#define TrackLocker(lockvar)

#endif

class MTPoolAllocator: public PoolAllocator
{
public:
	//! create and initialize a pool allocator
	//! \param poolid use poolid to distinguish more than one pool
	//! \param poolSize size of pre-allocated pool in kBytes, default 1MByte
	MTPoolAllocator(long poolid, u_long poolSize = 1024, u_long maxKindOfBucket = 10)
		: PoolAllocator(poolid, poolSize, maxKindOfBucket) TrackLockerInit(fCurrLockerId) {}
	//! destroy a pool only if its empty, i.e. all allocated bytes are freed
	virtual ~MTPoolAllocator() { }
	//! implement hook for freeing memory
	virtual inline void Free(void *vp) {
		TrackLocker(fCurrLockerId);
		PoolAllocator::Free(vp);
	}

protected:
	TrackLockerDef(fCurrLockerId);
	//!implement hook for allocating memory using bucketing
	virtual inline void *Alloc(u_long allocSize) {
		TrackLocker(fCurrLockerId);
		return PoolAllocator::Alloc(allocSize);
	}
};

#ifdef MEM_DEBUG
//------------- Utilities for Memory Tracking (multi threaded) --------------

MT_MemTracker::MT_MemTracker(const char *name)
	: MemTracker(name)
{
	if ( !CREATEMUTEX(fMutex) ) {
		SysLog::Error("Mutex create failed");
	}
}

MT_MemTracker::~MT_MemTracker()
{
	if ( !DELETEMUTEX(fMutex) ) {
		SysLog::Error("Mutex delete failed");
	}
}

void MT_MemTracker::TrackAlloc(u_long allocSz)
{
	if ( !LOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex lock failed");
	}
	MemTracker::TrackAlloc(allocSz);
	if ( !UNLOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex unlock failed");
	}
}

void MT_MemTracker::TrackFree(u_long allocSz)
{
	if ( !LOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex lock failed");
	}
	MemTracker::TrackFree(allocSz);
	if ( !UNLOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex unlock failed");
	}
}

l_long MT_MemTracker::CurrentlyAllocated()
{
	l_long l;
	if ( !LOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex lock failed");
	}
	l = fAllocated;
	if ( !UNLOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex lock failed");
	}
	return  l;
}

void MT_MemTracker::PrintStatistic()
{
	if ( !LOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex lock failed");
	}
	MemTracker::PrintStatistic();
	if ( !UNLOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex lock failed");
	}
}
#endif

class EXPORTDECL_MTFOUNDATION MTStorageHooks : public StorageHooks
{
public:
	virtual void Initialize();
	virtual void Finalize();
	virtual Allocator *Global();

	virtual Allocator *Current();
#ifdef MEM_DEBUG
	virtual MemTracker *MakeMemTracker(const char *name);
#endif
	static bool fgInitialized;
};

static MTStorageHooks sgMTHooks;

//---- MT_Storage ------------------------------------------
struct AllocList {
	Allocator *wdallocator;
	AllocList *next;
};

static AllocList *fgPoolAllocatorList = 0;
bool MTStorageHooks::fgInitialized = false; // flag for memorizing initialization

void MT_Storage::Initialize()
{
	StartTrace(MT_Storage.Initialize);
	// must be called before threading is activated
	static bool once = false;
	if (!once) {
		gsAllocatorInit	= new Mutex("AllocatorInit");
		Storage::SetHooks(&sgMTHooks);
		Storage::Initialize(); // re-init with MT hook

#ifdef MEM_DEBUG
		// switch to thread safe memory tracker
		Allocator *a = Storage::Global();
		if (a) {
			a->ReplaceMemTracker(Storage::MakeMemTracker("MTGlobalAllocator"));
		}
#endif
		once = true;
	}
}

void MT_Storage::RefAllocator(Allocator *wdallocator)
{
	StartTrace1(MT_Storage.RefAllocator, "Id:" << (wdallocator ? wdallocator->GetId() : -1L));
	if ( wdallocator ) {
		Initialize();	// used to initialize gsAllocatorInit Mutex
		// in mt case we need to control ref counting with mutexes
		MutexEntry me(*gsAllocatorInit);
		me.Use();

		AllocList *elmt = (AllocList *)::calloc(1, sizeof(AllocList));
		// catch memory allocation problem
		if (!elmt) {
			static const char crashmsg[] = "FATAL: MT_Storage::RefAllocator calloc failed. I will crash :-(\n";
			SysLog::WriteToStderr(crashmsg, sizeof(crashmsg));
			SysLog::Error("allocation failed for RefAllocator");
			return;
		}

		// normal case everything ok
		wdallocator->Ref();
		Trace("refcount is now:" << wdallocator->RefCnt());
		// update linked list
		elmt->wdallocator = wdallocator;
		elmt->next = fgPoolAllocatorList;
		fgPoolAllocatorList = elmt;
	}
	// silently ignore misuse of this api
}

void MT_Storage::UnrefAllocator(Allocator *wdallocator)
{
	StartTrace1(MT_Storage.UnrefAllocator, "Id:" << (wdallocator ? wdallocator->GetId() : -1L));
	if (wdallocator) {	// just to be robust wdallocator == 0 should not happen
		Initialize();	// used to initialize gsAllocatorInit Mutex
		MutexEntry me(*gsAllocatorInit);
		me.Use();
		wdallocator->Unref();
		Trace("refcount is now:" << wdallocator->RefCnt());

		if ( wdallocator->RefCnt() <= 0 ) {
			// remove pool allocator
			AllocList *elmt = fgPoolAllocatorList;
			AllocList *prev = fgPoolAllocatorList;

			while (elmt && (elmt->wdallocator != wdallocator)) {
				prev = elmt;
				elmt = elmt->next;
			}
			if ( elmt ) {
				if ( elmt == fgPoolAllocatorList ) {
					fgPoolAllocatorList = elmt->next;
				} else {
					prev->next = elmt->next;
				}

				delete elmt->wdallocator;
				::free(elmt);
			}
		}
	}
	// silently ignore misuse of this api
}

bool MT_Storage::RegisterThread(Allocator *wdallocator)
{
	StartTrace(MT_Storage.RegisterThread);
	// can only be used once for the same thread

	Allocator *oldAllocator = 0;

	// determine which allocator to use
	FindAllocator(oldAllocator);
	if (!oldAllocator) {
		return ! SETTLSDATA(MT_Storage::fgAllocatorKey, wdallocator);
	}
	return false;
}

Allocator *MT_Storage::MakePoolAllocator(u_long poolStorageSize, u_long numOfPoolBucketSizes, long lPoolId)
{
	StartTrace(MT_Storage.MakePoolAllocator);
	Allocator *newPoolAllocator = new MTPoolAllocator(lPoolId, poolStorageSize, numOfPoolBucketSizes);
	if (!newPoolAllocator) {
		String msg("allocation of PoolStorage: ");
		msg << (long)poolStorageSize << ", " << (long)numOfPoolBucketSizes << " failed";
		SysLog::Error(msg);
		return newPoolAllocator;
	}
	if (newPoolAllocator->RefCnt() <= -1) {
		// we managed to allocate a pool allocator
		// but the object failed to allocate the pool storage
		delete newPoolAllocator;
		newPoolAllocator = 0;
	}

	return newPoolAllocator;
}

void MTStorageHooks::Finalize()
{
	Initialize();	// used to initialize gsAllocatorInit Mutex
	// terminate pool allocators
	MutexEntry me(*gsAllocatorInit);
	me.Use();
	while (fgPoolAllocatorList) {
		AllocList *elmt = fgPoolAllocatorList;
		delete elmt->wdallocator;
		fgPoolAllocatorList = elmt->next;
		::free(elmt);
	}
	Storage::DoFinalize();
}

Allocator *MTStorageHooks::Global()
{
	return 	Storage::DoGlobal();
}

#ifdef MEM_DEBUG
MemTracker *MTStorageHooks::MakeMemTracker(const char *name)
{
	return new MT_MemTracker(name);
}
#endif

Allocator *MTStorageHooks::Current()
{
	Allocator *wdallocator = 0;

	// Storage::Current() might be called before Storage::Global()
	// therefore need to initialize here too
	Storage::Initialize();

	// determine which allocator to use
	FindAllocator(wdallocator);

	if (wdallocator) {
		return wdallocator;
	}

	return Storage::DoGlobal();
}

void MTStorageHooks::Initialize()
{
	if ( !fgInitialized ) { // need mutex??? not yet, we do not run MT
		// setup key used to store allocator in thread local storage
		if (THRKEYCREATE(MT_Storage::fgAllocatorKey, TLSDestructor)) {
			SysLog::Error("could not create TLS key");
		}
		fgInitialized = true;
		Storage::DoInitialize();
	}
}
<commit_msg>initializing message buffer<commit_after>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- interface include --------------------------------------------------------
#include "MT_Storage.h"

//--- standard modules used ----------------------------------------------------
#include "Threads.h"
#include "PoolAllocator.h"
#include "SysLog.h"
#include "Dbg.h"

//--- c-library modules used ---------------------------------------------------
#if !defined(WIN32)
#include <stdlib.h>
#endif

THREADKEY MT_Storage::fgAllocatorKey = 0;

#define FindAllocator(wdallocator)									\
		GETTLSDATA(MT_Storage::fgAllocatorKey, wdallocator, Allocator)

void TLSDestructor(void *)
{
	// destructor function for thread local storage
}

static Mutex *gsAllocatorInit = 0;		// protect all data structures used by MT_Storage

#if 0
#define TrackLockerInit(lockvar) , lockvar(0)
#define TrackLockerDef(lockvar)	volatile long lockvar

class EXPORTDECL_MTFOUNDATION CurrLockerEntry
{
	volatile long &frLockerId;
public:
	CurrLockerEntry(volatile long &rLockerId, const char *pFile, long lLine)
		: frLockerId(rLockerId) {
		CheckException(pFile, lLine);
		frLockerId = Thread::MyId();
	}
	~CurrLockerEntry() {
		frLockerId = 0;
	}
	inline void CheckException(const char *pFile, long lLine) {
		if ( frLockerId != 0 ) {
			long lOther = frLockerId;
			char buf[256] = { 0 };
			snprintf(buf, sizeof(buf), "\n%s:%d Another Locker entered already! otherThreadId:%d currentThreadId:%d\n", pFile, lLine, lOther, Thread::MyId());
			SysLog::WriteToStderr(buf, strlen(buf));
		}
	}
};

#define TrackLocker(lockvar)	CurrLockerEntry aEntry(lockvar, __FILE__, __LINE__)

#else

#define TrackLockerInit(lockvar)
#define TrackLockerDef(lockvar)
#define TrackLocker(lockvar)

#endif

class MTPoolAllocator: public PoolAllocator
{
public:
	//! create and initialize a pool allocator
	//! \param poolid use poolid to distinguish more than one pool
	//! \param poolSize size of pre-allocated pool in kBytes, default 1MByte
	MTPoolAllocator(long poolid, u_long poolSize = 1024, u_long maxKindOfBucket = 10)
		: PoolAllocator(poolid, poolSize, maxKindOfBucket) TrackLockerInit(fCurrLockerId) {}
	//! destroy a pool only if its empty, i.e. all allocated bytes are freed
	virtual ~MTPoolAllocator() { }
	//! implement hook for freeing memory
	virtual inline void Free(void *vp) {
		TrackLocker(fCurrLockerId);
		PoolAllocator::Free(vp);
	}

protected:
	TrackLockerDef(fCurrLockerId);
	//!implement hook for allocating memory using bucketing
	virtual inline void *Alloc(u_long allocSize) {
		TrackLocker(fCurrLockerId);
		return PoolAllocator::Alloc(allocSize);
	}
};

#ifdef MEM_DEBUG
//------------- Utilities for Memory Tracking (multi threaded) --------------

MT_MemTracker::MT_MemTracker(const char *name)
	: MemTracker(name)
{
	if ( !CREATEMUTEX(fMutex) ) {
		SysLog::Error("Mutex create failed");
	}
}

MT_MemTracker::~MT_MemTracker()
{
	if ( !DELETEMUTEX(fMutex) ) {
		SysLog::Error("Mutex delete failed");
	}
}

void MT_MemTracker::TrackAlloc(u_long allocSz)
{
	if ( !LOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex lock failed");
	}
	MemTracker::TrackAlloc(allocSz);
	if ( !UNLOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex unlock failed");
	}
}

void MT_MemTracker::TrackFree(u_long allocSz)
{
	if ( !LOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex lock failed");
	}
	MemTracker::TrackFree(allocSz);
	if ( !UNLOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex unlock failed");
	}
}

l_long MT_MemTracker::CurrentlyAllocated()
{
	l_long l;
	if ( !LOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex lock failed");
	}
	l = fAllocated;
	if ( !UNLOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex lock failed");
	}
	return  l;
}

void MT_MemTracker::PrintStatistic()
{
	if ( !LOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex lock failed");
	}
	MemTracker::PrintStatistic();
	if ( !UNLOCKMUTEX(fMutex) ) {
		SysLog::Error("Mutex lock failed");
	}
}
#endif

class EXPORTDECL_MTFOUNDATION MTStorageHooks : public StorageHooks
{
public:
	virtual void Initialize();
	virtual void Finalize();
	virtual Allocator *Global();

	virtual Allocator *Current();
#ifdef MEM_DEBUG
	virtual MemTracker *MakeMemTracker(const char *name);
#endif
	static bool fgInitialized;
};

static MTStorageHooks sgMTHooks;

//---- MT_Storage ------------------------------------------
struct AllocList {
	Allocator *wdallocator;
	AllocList *next;
};

static AllocList *fgPoolAllocatorList = 0;
bool MTStorageHooks::fgInitialized = false; // flag for memorizing initialization

void MT_Storage::Initialize()
{
	StartTrace(MT_Storage.Initialize);
	// must be called before threading is activated
	static bool once = false;
	if (!once) {
		gsAllocatorInit	= new Mutex("AllocatorInit");
		Storage::SetHooks(&sgMTHooks);
		Storage::Initialize(); // re-init with MT hook

#ifdef MEM_DEBUG
		// switch to thread safe memory tracker
		Allocator *a = Storage::Global();
		if (a) {
			a->ReplaceMemTracker(Storage::MakeMemTracker("MTGlobalAllocator"));
		}
#endif
		once = true;
	}
}

void MT_Storage::RefAllocator(Allocator *wdallocator)
{
	StartTrace1(MT_Storage.RefAllocator, "Id:" << (wdallocator ? wdallocator->GetId() : -1L));
	if ( wdallocator ) {
		Initialize();	// used to initialize gsAllocatorInit Mutex
		// in mt case we need to control ref counting with mutexes
		MutexEntry me(*gsAllocatorInit);
		me.Use();

		AllocList *elmt = (AllocList *)::calloc(1, sizeof(AllocList));
		// catch memory allocation problem
		if (!elmt) {
			static const char crashmsg[] = "FATAL: MT_Storage::RefAllocator calloc failed. I will crash :-(\n";
			SysLog::WriteToStderr(crashmsg, sizeof(crashmsg));
			SysLog::Error("allocation failed for RefAllocator");
			return;
		}

		// normal case everything ok
		wdallocator->Ref();
		Trace("refcount is now:" << wdallocator->RefCnt());
		// update linked list
		elmt->wdallocator = wdallocator;
		elmt->next = fgPoolAllocatorList;
		fgPoolAllocatorList = elmt;
	}
	// silently ignore misuse of this api
}

void MT_Storage::UnrefAllocator(Allocator *wdallocator)
{
	StartTrace1(MT_Storage.UnrefAllocator, "Id:" << (wdallocator ? wdallocator->GetId() : -1L));
	if (wdallocator) {	// just to be robust wdallocator == 0 should not happen
		Initialize();	// used to initialize gsAllocatorInit Mutex
		MutexEntry me(*gsAllocatorInit);
		me.Use();
		wdallocator->Unref();
		Trace("refcount is now:" << wdallocator->RefCnt());

		if ( wdallocator->RefCnt() <= 0 ) {
			// remove pool allocator
			AllocList *elmt = fgPoolAllocatorList;
			AllocList *prev = fgPoolAllocatorList;

			while (elmt && (elmt->wdallocator != wdallocator)) {
				prev = elmt;
				elmt = elmt->next;
			}
			if ( elmt ) {
				if ( elmt == fgPoolAllocatorList ) {
					fgPoolAllocatorList = elmt->next;
				} else {
					prev->next = elmt->next;
				}

				delete elmt->wdallocator;
				::free(elmt);
			}
		}
	}
	// silently ignore misuse of this api
}

bool MT_Storage::RegisterThread(Allocator *wdallocator)
{
	StartTrace(MT_Storage.RegisterThread);
	// can only be used once for the same thread

	Allocator *oldAllocator = 0;

	// determine which allocator to use
	FindAllocator(oldAllocator);
	if (!oldAllocator) {
		return ! SETTLSDATA(MT_Storage::fgAllocatorKey, wdallocator);
	}
	return false;
}

Allocator *MT_Storage::MakePoolAllocator(u_long poolStorageSize, u_long numOfPoolBucketSizes, long lPoolId)
{
	StartTrace(MT_Storage.MakePoolAllocator);
	Allocator *newPoolAllocator = new MTPoolAllocator(lPoolId, poolStorageSize, numOfPoolBucketSizes);
	if (!newPoolAllocator) {
		String msg("allocation of PoolStorage: ");
		msg << (long)poolStorageSize << ", " << (long)numOfPoolBucketSizes << " failed";
		SysLog::Error(msg);
		return newPoolAllocator;
	}
	if (newPoolAllocator->RefCnt() <= -1) {
		// we managed to allocate a pool allocator
		// but the object failed to allocate the pool storage
		delete newPoolAllocator;
		newPoolAllocator = 0;
	}

	return newPoolAllocator;
}

void MTStorageHooks::Finalize()
{
	Initialize();	// used to initialize gsAllocatorInit Mutex
	// terminate pool allocators
	MutexEntry me(*gsAllocatorInit);
	me.Use();
	while (fgPoolAllocatorList) {
		AllocList *elmt = fgPoolAllocatorList;
		delete elmt->wdallocator;
		fgPoolAllocatorList = elmt->next;
		::free(elmt);
	}
	Storage::DoFinalize();
}

Allocator *MTStorageHooks::Global()
{
	return 	Storage::DoGlobal();
}

#ifdef MEM_DEBUG
MemTracker *MTStorageHooks::MakeMemTracker(const char *name)
{
	return new MT_MemTracker(name);
}
#endif

Allocator *MTStorageHooks::Current()
{
	Allocator *wdallocator = 0;

	// Storage::Current() might be called before Storage::Global()
	// therefore need to initialize here too
	Storage::Initialize();

	// determine which allocator to use
	FindAllocator(wdallocator);

	if (wdallocator) {
		return wdallocator;
	}

	return Storage::DoGlobal();
}

void MTStorageHooks::Initialize()
{
	if ( !fgInitialized ) { // need mutex??? not yet, we do not run MT
		// setup key used to store allocator in thread local storage
		if (THRKEYCREATE(MT_Storage::fgAllocatorKey, TLSDestructor)) {
			SysLog::Error("could not create TLS key");
		}
		fgInitialized = true;
		Storage::DoInitialize();
	}
}
<|endoftext|>


<commit_before>#include "SystemCPU.hpp"
#include <iostream>

using namespace std;

int main()
{
	while (true)
	{

	SystemCpu syscpu;
	cout << syscpu.getCpuModeInfo() << endl;
}
	system("pause");
}

TCHAR* SystemCpu::getCpuModeInfo()
{
    HKEY key;
    TCHAR data[1024];
	DWORD dwSize;
	dwSize = sizeof(data) / sizeof(TCHAR);

	if (RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), &key) != ERROR_SUCCESS)
		throw -1;

	if (RegQueryValueEx(key, TEXT("ProcessorNameString"), NULL, NULL, (LPBYTE)data, &dwSize) != ERROR_SUCCESS)
		throw -2;

    RegCloseKey(key);

	return data;
}

int SystemCpu::getUsage(double &val)
{
	FILETIME sysIdle, sysKernel, sysUser;
	// sysKernel include IdleTime
	if (GetSystemTimes(&sysIdle, &sysKernel, &sysUser) == 0) // GetSystemTimes func FAILED return value is zero;
		return 0;

	if (prevSysIdle.dwLowDateTime != 0 && prevSysIdle.dwHighDateTime != 0)
	{
		ULONGLONG sysIdleDiff, sysKernelDiff, sysUserDiff;
		sysIdleDiff = SubtractTimes(sysIdle, prevSysIdle);
		sysKernelDiff = SubtractTimes(sysKernel, prevSysKernel);
		sysUserDiff = SubtractTimes(sysUser, prevSysUser);

		ULONGLONG sysTotal = sysKernelDiff + sysUserDiff;
		ULONGLONG kernelTotal = sysKernelDiff - sysIdleDiff; // kernelTime - IdleTime = kernelTime, because sysKernel include IdleTime

		if (sysTotal > 0) // sometimes kernelTime > idleTime
			val = (double)(((kernelTotal + sysUserDiff) * 100.0) / sysTotal);
	}

	prevSysIdle = sysIdle;
	prevSysKernel = sysKernel;
	prevSysUser = sysUser;

	return 1;
}

// 100 - total = IDLE CPU Usage
int SystemCpu::getIdleUsage(double &val)
{
	double curUsage;
	if (getUsage(curUsage) == 0)
		return 0;

	val = 100.0 - curUsage;

	return 1;
}

// TIME DIFF FUNC
ULONGLONG SystemCpu::SubtractTimes(const FILETIME one, const FILETIME two)
{
	LARGE_INTEGER a, b;
	a.LowPart = one.dwLowDateTime;
	a.HighPart = one.dwHighDateTime;

	b.LowPart = two.dwLowDateTime;
	b.HighPart = two.dwHighDateTime;

	return a.QuadPart - b.QuadPart;
}<commit_msg>main func remove in SystemCpu.cpp<commit_after>#include "SystemCPU.hpp"

TCHAR* SystemCpu::getCpuModeInfo()
{
    HKEY key;
    TCHAR data[1024];
	DWORD dwSize;
	dwSize = sizeof(data) / sizeof(TCHAR);

	if (RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), &key) != ERROR_SUCCESS)
		throw -1;

	if (RegQueryValueEx(key, TEXT("ProcessorNameString"), NULL, NULL, (LPBYTE)data, &dwSize) != ERROR_SUCCESS)
		throw -2;

    RegCloseKey(key);

	return data;
}

int SystemCpu::getUsage(double &val)
{
	FILETIME sysIdle, sysKernel, sysUser;
	// sysKernel include IdleTime
	if (GetSystemTimes(&sysIdle, &sysKernel, &sysUser) == 0) // GetSystemTimes func FAILED return value is zero;
		return 0;

	if (prevSysIdle.dwLowDateTime != 0 && prevSysIdle.dwHighDateTime != 0)
	{
		ULONGLONG sysIdleDiff, sysKernelDiff, sysUserDiff;
		sysIdleDiff = SubtractTimes(sysIdle, prevSysIdle);
		sysKernelDiff = SubtractTimes(sysKernel, prevSysKernel);
		sysUserDiff = SubtractTimes(sysUser, prevSysUser);

		ULONGLONG sysTotal = sysKernelDiff + sysUserDiff;
		ULONGLONG kernelTotal = sysKernelDiff - sysIdleDiff; // kernelTime - IdleTime = kernelTime, because sysKernel include IdleTime

		if (sysTotal > 0) // sometimes kernelTime > idleTime
			val = (double)(((kernelTotal + sysUserDiff) * 100.0) / sysTotal);
	}

	prevSysIdle = sysIdle;
	prevSysKernel = sysKernel;
	prevSysUser = sysUser;

	return 1;
}

// 100 - total = IDLE CPU Usage
int SystemCpu::getIdleUsage(double &val)
{
	double curUsage;
	if (getUsage(curUsage) == 0)
		return 0;

	val = 100.0 - curUsage;

	return 1;
}

// TIME DIFF FUNC
ULONGLONG SystemCpu::SubtractTimes(const FILETIME one, const FILETIME two)
{
	LARGE_INTEGER a, b;
	a.LowPart = one.dwLowDateTime;
	a.HighPart = one.dwHighDateTime;

	b.LowPart = two.dwLowDateTime;
	b.HighPart = two.dwHighDateTime;

	return a.QuadPart - b.QuadPart;
}<|endoftext|>


<commit_before>#include "results.h"
#include "engine.h"
#include <cstdint>
#include <string>
#include <vector>
#include <napi.h>

// all/mask percent to js
Napi::Array
ToJs(const Napi::Env &env, const std::string &name, const uint_fast32_t diffsPerc, const uint_fast32_t percentResult) {
    Napi::Array resultsJs = Napi::Array::New(env);
    if (percentResult >= diffsPerc) {
        Napi::Object obj = Napi::Object::New(env);
        obj.Set("name", name);
        obj.Set("percent", percentResult);
        resultsJs.Set(0u, obj);
    }
    return resultsJs;
}

// regions percent to js
Napi::Array
ToJs(const Napi::Env &env, const uint_fast32_t regionsLen, const std::vector<Region> &regionVec,
     const std::vector<uint_fast32_t> &percentResultVec) {
    Napi::Array resultsJs = Napi::Array::New(env);
    for (uint_fast32_t r = 0, j = 0, percent = 0; r < regionsLen; r++) {
        percent = percentResultVec[r];
        Region region = regionVec[r];
        if (region.percent > percent) continue;
        Napi::Object obj = Napi::Object::New(env);
        obj.Set("name", region.name);
        obj.Set("percent", percent);
        resultsJs.Set(j++, obj);
    }
    return resultsJs;
}

// all/mask bounds to js
Napi::Array
ToJs(const Napi::Env &env, const std::string &name, const uint_fast32_t diffsPerc, const BoundsResult &boundsResult) {
    Napi::Array resultsJs = Napi::Array::New(env);
    if (boundsResult.percent >= diffsPerc) {
        Napi::Object obj = Napi::Object::New(env);
        obj.Set("name", name);
        obj.Set("percent", boundsResult.percent);
        obj.Set("minX", boundsResult.minX);
        obj.Set("maxX", boundsResult.maxX);
        obj.Set("minY", boundsResult.minY);
        obj.Set("maxY", boundsResult.maxY);
        resultsJs.Set(0u, obj);
    }
    return resultsJs;
}

// regions bounds to js
Napi::Array
ToJs(const Napi::Env &env, const uint_fast32_t regionsLen, const std::vector<Region> &regionVec,
     const std::vector<BoundsResult> &boundsResultVec) {
    Napi::Array resultsJs = Napi::Array::New(env);
    for (uint_fast32_t r = 0, j = 0; r < regionsLen; r++) {
        BoundsResult boundsResult = boundsResultVec[r];
        Region region = regionVec[r];
        if (region.percent > boundsResult.percent) continue;
        Napi::Object obj = Napi::Object::New(env);
        obj.Set("name", region.name);
        obj.Set("percent", boundsResult.percent);
        obj.Set("minX", boundsResult.minX);
        obj.Set("maxX", boundsResult.maxX);
        obj.Set("minY", boundsResult.minY);
        obj.Set("maxY", boundsResult.maxY);
        resultsJs.Set(j++, obj);
    }
    return resultsJs;
}<commit_msg>removed temp var<commit_after>#include "results.h"
#include "engine.h"
#include <cstdint>
#include <string>
#include <vector>
#include <napi.h>

// all/mask percent to js
Napi::Array
ToJs(const Napi::Env &env, const std::string &name, const uint_fast32_t diffsPerc, const uint_fast32_t percentResult) {
    Napi::Array resultsJs = Napi::Array::New(env);
    if (percentResult >= diffsPerc) {
        Napi::Object obj = Napi::Object::New(env);
        obj.Set("name", name);
        obj.Set("percent", percentResult);
        resultsJs.Set(0u, obj);
    }
    return resultsJs;
}

// regions percent to js
Napi::Array
ToJs(const Napi::Env &env, const uint_fast32_t regionsLen, const std::vector<Region> &regionVec,
     const std::vector<uint_fast32_t> &percentResultVec) {
    Napi::Array resultsJs = Napi::Array::New(env);
    for (uint_fast32_t r = 0, j = 0; r < regionsLen; r++) {
        if (regionVec[r].percent > percentResultVec[r]) continue;
        Napi::Object obj = Napi::Object::New(env);
        obj.Set("name", regionVec[r].name);
        obj.Set("percent", percentResultVec[r]);
        resultsJs.Set(j++, obj);
    }
    return resultsJs;
}

// all/mask bounds to js
Napi::Array
ToJs(const Napi::Env &env, const std::string &name, const uint_fast32_t diffsPerc, const BoundsResult &boundsResult) {
    Napi::Array resultsJs = Napi::Array::New(env);
    if (boundsResult.percent >= diffsPerc) {
        Napi::Object obj = Napi::Object::New(env);
        obj.Set("name", name);
        obj.Set("percent", boundsResult.percent);
        obj.Set("minX", boundsResult.minX);
        obj.Set("maxX", boundsResult.maxX);
        obj.Set("minY", boundsResult.minY);
        obj.Set("maxY", boundsResult.maxY);
        resultsJs.Set(0u, obj);
    }
    return resultsJs;
}

// regions bounds to js
Napi::Array
ToJs(const Napi::Env &env, const uint_fast32_t regionsLen, const std::vector<Region> &regionVec,
     const std::vector<BoundsResult> &boundsResultVec) {
    Napi::Array resultsJs = Napi::Array::New(env);
    for (uint_fast32_t r = 0, j = 0; r < regionsLen; r++) {
        if (regionVec[r].percent > boundsResultVec[r].percent) continue;
        Napi::Object obj = Napi::Object::New(env);
        obj.Set("name", regionVec[r].name);
        obj.Set("percent", boundsResultVec[r].percent);
        obj.Set("minX", boundsResultVec[r].minX);
        obj.Set("maxX", boundsResultVec[r].maxX);
        obj.Set("minY", boundsResultVec[r].minY);
        obj.Set("maxY", boundsResultVec[r].maxY);
        resultsJs.Set(j++, obj);
    }
    return resultsJs;
}<|endoftext|>