<commit_before>/*
 * Copyright (c) 2016 Shanghai Jiao Tong University.
 *     All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an "AS
 *  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 *  express or implied.  See the License for the specific language
 *  governing permissions and limitations under the License.
 *
 * For more about this software visit:
 *
 *      http://ipads.se.sjtu.edu.cn/projects/wukong.html
 *
 */

#pragma once

#include <iostream>
#include <string>
#include <set>
#include <boost/unordered_map.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

#include "config.hpp"
#include "proxy.hpp"
#include "logger.hpp"

using namespace std;

// communicate between proxy threads
TCP_Adaptor *con_adaptor;

template<typename T>
static void console_send(int sid, int tid, T &r) {
	std::stringstream ss;
	boost::archive::binary_oarchive oa(ss);
	oa << r;
	con_adaptor->send(sid, tid, ss.str());
}

template<typename T>
static T console_recv(int tid) {
	std::string str;
	str = con_adaptor->recv(tid);

	std::stringstream ss;
	ss << str;

	boost::archive::binary_iarchive ia(ss);
	T r;
	ia >> r;
	return r;
}

static void console_barrier(int tid)
{
	static int _curr = 0;
	static __thread int _next = 1;

	// inter-server barrier
	if (tid == 0)
		MPI_Barrier(MPI_COMM_WORLD);

	// intra-server barrier
	__sync_fetch_and_add(&_curr, 1);
	while (_curr < _next)
		usleep(1); // wait
	_next += global_num_proxies; // next barrier
}

void print_help(void)
{
	cout << "These are common Wukong commands: " << endl;
	cout << "    help                display help infomation" << endl;
	cout << "    quit                quit from console" << endl;
	cout << "    config <args>       run commands on config" << endl;
	cout << "        -v                  print current config" << endl;
	cout << "        -l <file>           load config items from <file>" << endl;
	cout << "        -s <string>         set config items by <str> (format: item1=val1&item2=...)" << endl;
	cout << "    sparql <args>       run SPARQL queries" << endl;
	cout << "        -f <file> [<args>]  a single query from <file>" << endl;
	cout << "           -n <num>            run <num> times" << endl;
	cout << "           -v <num>            print at most <num> lines of results" << endl;
	cout << "           -w <file>           write results into <file>" << endl;
	cout << "        -b <file>           a set of queries configured by <file>" << endl;
}

// the master proxy is the 1st proxy of the 1st server (i.e., sid == 0 and tid == 0)
#define IS_MASTER(_p) ((_p)->sid == 0 && (_p)->tid == 0)
#define PRINT_ID(_p) (cout << "[" << (_p)->sid << "-" << (_p)->tid << "]$ ")

static void file2str(string fname, string &str)
{
	ifstream file(fname.c_str());
	if (!file) {
		cout << "ERROR: " << fname << " does not exist." << endl;
		return;
	}

	string line;
	while (std::getline(file, line))
		str += line + " ";
}

static void args2str(string &str)
{
	size_t found = str.find_first_of("=&");
	while (found != string::npos) {
		str[found] = ' ';
		found = str.find_first_of("=&", found + 1);
	}
}

/**
 * The Wukong's console is co-located with the main proxy (the 1st proxy thread on the 1st server)
 * and provide a simple interactive cmdline to tester
 */
void run_console(Proxy *proxy)
{
	console_barrier(proxy->tid);
	if (IS_MASTER(proxy))
		cout << endl
		     << "Input \'help\'' command to get more information"
		     << endl
		     << endl;

	while (true) {
		console_barrier(proxy->tid);
next:
		string cmd;
		if (IS_MASTER(proxy)) {
			cout << "> ";
			std::getline(std::cin, cmd);

			// trim input
			size_t pos = cmd.find_first_not_of(" \t"); // trim blanks from head
			if (pos == string::npos) goto next;
			cmd.erase(0, pos);

			pos = cmd.find_last_not_of(" \t");  // trim blanks from tail
			cmd.erase(pos + 1, cmd.length() - (pos + 1));

			// only run <cmd> on the master console
			if (cmd == "help") {
				print_help();
				goto next;
			}

			// send <cmd> to all consoles
			for (int i = 0; i < global_num_servers; i++) {
				for (int j = 0; j < global_num_proxies; j++) {
					if (i == 0 && j == 0) continue ;
					console_send<string>(i, j, cmd);
				}
			}
		} else {
			// recieve <cmd>
			cmd = console_recv<string>(proxy->tid);
		}

		// run <cmd> on all consoles
		if (cmd == "quit" || cmd == "q") {
			if (proxy->tid == 0)
				exit(0); // each server exits once by the 1st console
		} else {
			std::stringstream cmd_ss(cmd);
			std::string token;

			// get keyword of command
			cmd_ss >> token;
			if (token == "config") {
				cmd_ss >> token;

				if (token == "-v") {
					// only show config on the master console
					if (IS_MASTER(proxy))
						print_config();
				} else if (token == "-l") {
					// each server load config file once by the 1st console
					if (proxy->tid != 0) continue;

					string fname;
					if (cmd_ss >> fname) {
						string str;
						if (IS_MASTER(proxy)) {
							file2str(fname, str);

							// send <str> to all consoles
							for (int i = 1; i < global_num_servers; i++)
								console_send<string>(i, 0, str);
						} else {
							// recieve <str>
							str = console_recv<string>(proxy->tid);
						}

						if (!str.empty()) {
							reload_config(str);
						} else {
							if (IS_MASTER(proxy))
								cout << "Failed to load config file: " << fname << endl;
						}
					} else {
						goto failed;
					}
				} else if (token == "-s") {
					// each server set config item once by the 1st console
					if (proxy->tid != 0) continue;

					string str;
					if (cmd_ss >> str) {
						if (IS_MASTER(proxy)) {
							args2str(str);

							// send <str> to all consoles
							for (int i = 1; i < global_num_servers; i++)
								console_send<string>(i, 0, str);
						} else {
							// recieve <str>
							str = console_recv<string>(proxy->tid);
						}

						reload_config(str);
					} else {
						goto failed;
					}
				} else {
					goto failed;
				}
			} else if (token == "sparql") { // handle SPARQL queries
				string fname, bfname, ofname;
				int cnt = 1, nlines = 0;
				bool f_enable = false, b_enable = false, o_enable = false;

				// parse parameters
				while (cmd_ss >> token) {
					if (token == "-f") {
						cmd_ss >> fname;
						f_enable = true;
					} else if (token == "-n") {
						cmd_ss >> cnt;
					} else if (token == "-v") {
						cmd_ss >> nlines;
					} else if (token == "-o") {
						cmd_ss >> ofname;
						o_enable = true;
					} else if (token == "-b") {
						cmd_ss >> bfname;
						b_enable = true;
					} else {
						goto failed;
					}
				}

				if (!f_enable && !b_enable) goto failed; // meaningless args for SPARQL queries

				if (f_enable) {
					// use the main proxy thread to run a single query
					if (IS_MASTER(proxy)) {
						ifstream ifs(fname);
						if (!ifs.good()) {
							cout << "Query file not found: " << fname << endl;
							continue ;
						}

						ofstream ofs(ofname, std::ios::out);
						if (o_enable && !ofs.good()) {
							cout << "Can't open/create output file: " << ofname << endl;
							continue;
						}

						if (global_silent) {
							if (nlines > 0) {
								cout << "Can't print results (-v) with global_silent." << endl;
								continue;
							}

							if (o_enable) {
								cout << "Can't output results (-w) with global_silent." << endl;
								continue;
							}
						}

						request_or_reply reply;
						Logger logger;
						int ret = proxy->run_single_query(ifs, cnt, reply, logger);
						if (ret != 0) {
							cout << "Failed to run the query (ERROR: " << ret << ")!" << endl;
							continue;
						}

						// print or dump results
						logger.print_latency(cnt);
						cout << "(last) result size: " << reply.row_num << endl;
						if (!global_silent && !reply.blind) {
							if (nlines > 0)
								proxy->print_result(reply, min(reply.row_num, nlines));

							if (o_enable)
								proxy->dump_result(reply, ofs);
						}
					}
				}

				if (b_enable) {
					Logger logger;

					// dedicate the master frontend worker to run a single query
					// and others to run a set of queries if '-f' is enabled
					if (!f_enable || !IS_MASTER(proxy)) {
						ifstream ifs(bfname);
						if (!ifs.good()) {
							PRINT_ID(proxy);
							cout << "Configure file not found: " << bfname << endl;
							continue;
						}
						proxy->nonblocking_run_batch_query(ifs, logger);
						//proxy->run_batch_query(ifs, logger);
					}

					console_barrier(proxy->tid);

					// print a statistic of runtime for the batch processing on all servers
					if (IS_MASTER(proxy)) {
						for (int i = 0; i < global_num_servers * global_num_proxies - 1; i++) {
							Logger other = console_recv<Logger>(proxy->tid);
							logger.merge(other);
						}
						logger.print_rdf();
						logger.print_thpt();
					} else {
						// send logs to the master proxy
						console_send<Logger>(0, 0, logger);
					}
				}
			} else {
failed:
				if (IS_MASTER(proxy)) {
					cout << "Failed to run the command: " << cmd << endl;
					print_help();
				}
			}
		}
	}
}
<commit_msg>config command done<commit_after>/*
 * Copyright (c) 2016 Shanghai Jiao Tong University.
 *     All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an "AS
 *  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 *  express or implied.  See the License for the specific language
 *  governing permissions and limitations under the License.
 *
 * For more about this software visit:
 *
 *      http://ipads.se.sjtu.edu.cn/projects/wukong.html
 *
 */

#pragma once

#include <iostream>
#include <string>
#include <set>
#include <boost/unordered_map.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

#include "config.hpp"
#include "proxy.hpp"
#include "logger.hpp"

using namespace std;

// communicate between proxy threads
TCP_Adaptor *con_adaptor;

template<typename T>
static void console_send(int sid, int tid, T &r) {
	std::stringstream ss;
	boost::archive::binary_oarchive oa(ss);
	oa << r;
	con_adaptor->send(sid, tid, ss.str());
}

template<typename T>
static T console_recv(int tid) {
	std::string str;
	str = con_adaptor->recv(tid);

	std::stringstream ss;
	ss << str;

	boost::archive::binary_iarchive ia(ss);
	T r;
	ia >> r;
	return r;
}

static void console_barrier(int tid)
{
	static int _curr = 0;
	static __thread int _next = 1;

	// inter-server barrier
	if (tid == 0)
		MPI_Barrier(MPI_COMM_WORLD);

	// intra-server barrier
	__sync_fetch_and_add(&_curr, 1);
	while (_curr < _next)
		usleep(1); // wait
	_next += global_num_proxies; // next barrier
}

void print_help(void)
{
	cout << "These are common Wukong commands: " << endl;
	cout << "    help                display help infomation" << endl;
	cout << "    quit                quit from console" << endl;
	cout << "    config <args>       run commands on config" << endl;
	cout << "        -v                  print current config" << endl;
	cout << "        -l <file>           load config items from <file>" << endl;
	cout << "        -s <string>         set config items by <str> (format: item1=val1&item2=...)" << endl;
	cout << "    sparql <args>       run SPARQL queries" << endl;
	cout << "        -f <file> [<args>]  a single query from <file>" << endl;
	cout << "           -n <num>            run <num> times" << endl;
	cout << "           -v <num>            print at most <num> lines of results" << endl;
	cout << "           -w <file>           write results into <file>" << endl;
	cout << "        -b <file>           a set of queries configured by <file>" << endl;
}

// the master proxy is the 1st proxy of the 1st server (i.e., sid == 0 and tid == 0)
#define IS_MASTER(_p) ((_p)->sid == 0 && (_p)->tid == 0)
#define PRINT_ID(_p) (cout << "[" << (_p)->sid << "-" << (_p)->tid << "]$ ")

static void file2str(string fname, string &str)
{
	ifstream file(fname.c_str());
	if (!file) {
		cout << "ERROR: " << fname << " does not exist." << endl;
		return;
	}

	string line;
	while (std::getline(file, line))
		str += line + " ";
}

static void args2str(string &str)
{
	size_t found = str.find_first_of("=&");
	while (found != string::npos) {
		str[found] = ' ';
		found = str.find_first_of("=&", found + 1);
	}
}

/**
 * The Wukong's console is co-located with the main proxy (the 1st proxy thread on the 1st server)
 * and provide a simple interactive cmdline to tester
 */
void run_console(Proxy *proxy)
{
	console_barrier(proxy->tid);
	if (IS_MASTER(proxy))
		cout << endl
		     << "Input \'help\'' command to get more information"
		     << endl
		     << endl;

	while (true) {
		console_barrier(proxy->tid);
next:
		string cmd;
		if (IS_MASTER(proxy)) {
			cout << "> ";
			std::getline(std::cin, cmd);

			// trim input
			size_t pos = cmd.find_first_not_of(" \t"); // trim blanks from head
			if (pos == string::npos) goto next;
			cmd.erase(0, pos);

			pos = cmd.find_last_not_of(" \t");  // trim blanks from tail
			cmd.erase(pos + 1, cmd.length() - (pos + 1));

			// only run <cmd> on the master console
			if (cmd == "help") {
				print_help();
				goto next;
			}

			// send <cmd> to all consoles
			for (int i = 0; i < global_num_servers; i++) {
				for (int j = 0; j < global_num_proxies; j++) {
					if (i == 0 && j == 0) continue ;
					console_send<string>(i, j, cmd);
				}
			}
		} else {
			// recieve <cmd>
			cmd = console_recv<string>(proxy->tid);
		}

		// run <cmd> on all consoles
		if (cmd == "quit" || cmd == "q") {
			if (proxy->tid == 0)
				exit(0); // each server exits once by the 1st console
		} else {
			std::stringstream cmd_ss(cmd);
			std::string token;

			// get keyword of command
			cmd_ss >> token;
			if (token == "config") {
				if (proxy->tid != 0) continue;

				string fname, str;
				bool v_enable = false, l_enable = false, s_enable = false;

				// parse parameters
				while (cmd_ss >> token) {
					if (token == "-v") {
						v_enable = true;
					} else if (token == "-l") {
						l_enable = true;
						if (!(cmd_ss >> fname)) goto failed;
					} else if (token == "-s") {
						s_enable = true;
						if (!(cmd_ss >> str)) goto failed;
					} else {
						goto failed;
					}
				}

				if (v_enable) { // -v
					if (IS_MASTER(proxy))
						print_config();
				} else if (l_enable || s_enable) { // -l <file> or -s <str>
					if (IS_MASTER(proxy)) {
						if (l_enable) // -l
							file2str(fname, str);
						else if (s_enable) // -s
							args2str(str);

						// send <str> to all consoles
						for (int i = 1; i < global_num_servers; i++)
							console_send<string>(i, 0, str);
					} else {
						// recieve <str>
						str = console_recv<string>(proxy->tid);
					}

					if (!str.empty()) {
						reload_config(str);
					} else {
						if (IS_MASTER(proxy))
							cout << "Failed to load config file: " << fname << endl;
					}
				} else {
					goto failed;
				}
			} else if (token == "sparql") { // handle SPARQL queries
				string fname, bfname, ofname;
				int cnt = 1, nlines = 0;
				bool f_enable = false, b_enable = false, o_enable = false;

				// parse parameters
				while (cmd_ss >> token) {
					if (token == "-f") {
						cmd_ss >> fname;
						f_enable = true;
					} else if (token == "-n") {
						cmd_ss >> cnt;
					} else if (token == "-v") {
						cmd_ss >> nlines;
					} else if (token == "-o") {
						cmd_ss >> ofname;
						o_enable = true;
					} else if (token == "-b") {
						cmd_ss >> bfname;
						b_enable = true;
					} else {
						goto failed;
					}
				}

				if (!f_enable && !b_enable) goto failed; // meaningless args for SPARQL queries

				if (f_enable) { // -f <file>
					// use the main proxy thread to run a single query
					if (IS_MASTER(proxy)) {
						ifstream ifs(fname);
						if (!ifs.good()) {
							cout << "Query file not found: " << fname << endl;
							continue ;
						}

						ofstream ofs(ofname, std::ios::out);
						if (o_enable && !ofs.good()) {
							cout << "Can't open/create output file: " << ofname << endl;
							continue;
						}

						if (global_silent) {
							if (nlines > 0) {
								cout << "Can't print results (-v) with global_silent." << endl;
								continue;
							}

							if (o_enable) {
								cout << "Can't output results (-w) with global_silent." << endl;
								continue;
							}
						}

						request_or_reply reply;
						Logger logger;
						int ret = proxy->run_single_query(ifs, cnt, reply, logger);
						if (ret != 0) {
							cout << "Failed to run the query (ERROR: " << ret << ")!" << endl;
							continue;
						}

						// print or dump results
						logger.print_latency(cnt);
						cout << "(last) result size: " << reply.row_num << endl;
						if (!global_silent && !reply.blind) {
							if (nlines > 0)
								proxy->print_result(reply, min(reply.row_num, nlines));

							if (o_enable)
								proxy->dump_result(reply, ofs);
						}
					}
				}

				if (b_enable) { // -b <config>
					Logger logger;

					// dedicate the master frontend worker to run a single query
					// and others to run a set of queries if '-f' is enabled
					if (!f_enable || !IS_MASTER(proxy)) {
						ifstream ifs(bfname);
						if (!ifs.good()) {
							PRINT_ID(proxy);
							cout << "Configure file not found: " << bfname << endl;
							continue;
						}
						proxy->nonblocking_run_batch_query(ifs, logger);
						//proxy->run_batch_query(ifs, logger);
					}

					console_barrier(proxy->tid);

					// print a statistic of runtime for the batch processing on all servers
					if (IS_MASTER(proxy)) {
						for (int i = 0; i < global_num_servers * global_num_proxies - 1; i++) {
							Logger other = console_recv<Logger>(proxy->tid);
							logger.merge(other);
						}
						logger.print_rdf();
						logger.print_thpt();
					} else {
						// send logs to the master proxy
						console_send<Logger>(0, 0, logger);
					}
				}
			} else {
failed:
				if (IS_MASTER(proxy)) {
					cout << "Failed to run the command: " << cmd << endl;
					print_help();
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "json.h"

#include "gtest/gtest.h"

using namespace json;

TEST(without, non_empty) {
  EXPECT_EQ("abc", without('<', '>', "<abc>"));
}

TEST(without, empty) {
  EXPECT_EQ("", without('<', '>', "<>"));
}

TEST(without, exception_without_opening_bracket) {
  EXPECT_THROW(without('<', '>', "abc>"), std::runtime_error);
}

TEST(without, exception_without_closing_bracket) {
  EXPECT_THROW(without('<', '>', "<abc"), std::runtime_error);
}

TEST(withoutCurly, non_empty) {
  EXPECT_EQ("abc", withoutCurly("{abc}"));
}

TEST(withoutRect, non_empty) {
  EXPECT_EQ("abc", withoutRect("[abc]"));
}

TEST(withoutQuot, non_empty) {
  EXPECT_EQ("abc", withoutQuot("\"abc\""));
}

TEST(find_element_delimiter, simple) {
  EXPECT_EQ(1, findListDelimiter("a,b"));
}

TEST(find_element_delimiter, nested) {
  EXPECT_EQ(5, findListDelimiter("{a,b},c"));
}

TEST(trimmed, without_spaces) {
  EXPECT_EQ("hello", trimmed("hello"));
}

TEST(trimmed, leading_spaces) {
  EXPECT_EQ("hello", trimmed("   hello"));
}

TEST(trimmed, trailing_spaces) {
  EXPECT_EQ("hello", trimmed("hello   "));
}

TEST(trimmed, one_space) {
  EXPECT_EQ("", trimmed(" "));
}

TEST(trimmed, two_spaces) {
  EXPECT_EQ("", trimmed(" "));
}

TEST(to_json, fromString) {
  EXPECT_EQ("\"text\"", to_json("text"));
}

TEST(from_json, toString) {
  std::string result;
  from_json(" \"text\" ", result);
  EXPECT_EQ("text", result);
}

TEST(to_json, fromStdString) {
  EXPECT_EQ("\"text\"", to_json(std::string("text")));
}

TEST(to_json, fromTrue) {
  EXPECT_EQ("true", to_json(true));
}

TEST(from_json, toTrue) {
  bool result;
  from_json("true", result);
  EXPECT_EQ(true, result);
}

TEST(to_json, fromFalse) {
  EXPECT_EQ("false", to_json(false));
}

TEST(from_json, toFalse) {
  bool result;
  from_json("false", result);
  EXPECT_EQ(false, result);
}

TEST(to_json, fromInt) {
  EXPECT_EQ("-123", to_json(-123));
}

TEST(from_json, toInt) {
  int result;
  from_json("-123", result);
  EXPECT_EQ(-123, result);
}

TEST(to_json, fromUInt) {
  EXPECT_EQ("123", to_json(123u));
}

TEST(from_json, toUInt) {
  unsigned int result;
  from_json("123", result);
  EXPECT_EQ(123, result);
}

TEST(to_json, fromDouble) {
  EXPECT_EQ("1.23", to_json(1.23));
}

TEST(to_json, fromNaturalDouble) {
  EXPECT_EQ("3", to_json(3));
}

TEST(to_json, fromNegativeDouble) {
  EXPECT_EQ("-3.141", to_json(-3.141));
}

TEST(from_json, toDouble) {
  double result;
  from_json("1.23", result);
  EXPECT_DOUBLE_EQ(1.23, result);
}

TEST(from_json, toNaturalDouble) {
  double result;
  from_json("3", result);
  EXPECT_DOUBLE_EQ(3, result);
}

TEST(from_json, toNegativeDouble) {
  double result;
  from_json("-3.141", result);
  EXPECT_DOUBLE_EQ(-3.141, result);
}

TEST(to_json, fromEmptyList) {
  EXPECT_EQ("[]", to_json(std::list<int>()));
}

TEST(from_json, toEmptyList) {
  std::list<int> result;
  from_json("[ ]", result);
  EXPECT_EQ(0, result.size());
}

TEST(to_json, fromListOfInts) {
  auto l = std::list<int>({1,2,3});
  EXPECT_EQ("[1,2,3]", to_json(l));
}

TEST(from_json, toListOfInts) {
  std::list<int> result;
  from_json("[1,2,3]", result);
  EXPECT_EQ(3, result.size());
  auto it = result.begin();
  EXPECT_EQ(1, *it++);
  EXPECT_EQ(2, *it++);
  EXPECT_EQ(3, *it++);
}

TEST(to_json, fromListOfStrings) {
  auto l = std::list<std::string>({"a", "b", "c"});
  EXPECT_EQ("[\"a\",\"b\",\"c\"]", to_json(l));
}

TEST(from_json, toListOfStrings) {
  std::list<std::string> result;
  from_json("[\"a\",\"b\",\"c\"]", result);
  EXPECT_EQ(3, result.size());
  auto it = result.begin();
  EXPECT_EQ("a", *it++);
  EXPECT_EQ("b", *it++);
  EXPECT_EQ("c", *it++);
}

namespace {
class Object {
  int a_{0};
  int b_{0};
 public:
  Object() = default;
  Object(int a, int b) : a_(a), b_(b) { }

  bool operator==(const Object& rhs) const {
    return a_ == rhs.a_
        && b_ == rhs.b_;
  }

  std::string to_json() const {
    return ::to_json("a", a_) + "," + ::to_json("b", b_);
  }

  void from_json(const std::string& j) {
    ::from_json(j, "a", a_);
    ::from_json(j, "b", b_);
  }
};

};

TEST(to_json, fromObject) {
  EXPECT_EQ("{\"a\":1,\"b\":2}", to_json(Object(1,2)));
}

TEST(from_json, toObjectOriginalOrder) {
  Object result;
  from_json("{\"a\":1,\"b\":2}", result);
  EXPECT_EQ(Object(1, 2), result);
}

TEST(from_json, toObjectDifferentOrder) {
  Object result;
  from_json("{\"b\":2,\"a\":1}", result);
  EXPECT_EQ(Object(1, 2), result);
}

namespace {
class ObjectObject {
  Object obj_;
 public:
  ObjectObject() = default;
  ObjectObject(int a, int b) : obj_(a, b) { }

  bool operator==(const ObjectObject& rhs) const {
    return obj_ == rhs.obj_;
  }

  std::string to_json() const {
    return ::to_json("obj", obj_);
  }

  void from_json(const std::string& j) {
    ::from_json(j, "obj", obj_);
  }
};
}

TEST(to_json, fromObjectWithObject) {
  EXPECT_EQ("{\"obj\":{\"a\":1,\"b\":2}}", to_json(ObjectObject(1,2)));
}

TEST(from_json, toObjectWithObject) {
  ObjectObject result;
  from_json("{\"obj\":{\"a\":1,\"b\":2}}", result);
  EXPECT_EQ(ObjectObject(1,2), result);
}

namespace {
class ObjectWithLists {
  std::list<int> a_;
  std::list<int> b_;
 public:
  ObjectWithLists() = default;
  ObjectWithLists(std::list<int> a, std::list<int> b) : a_(a), b_(b) { }

  bool operator==(const ObjectWithLists& rhs) const {
    return a_ == rhs.a_
        && b_ == rhs.b_;
  }

  std::string to_json() const {
    return ::to_json("a", a_) + ","
        + ::to_json("b", b_);
  }

  void from_json(const std::string& j) {
    ::from_json(j, "a", a_);
    ::from_json(j, "b", b_);
  }
};
}

TEST(to_json, fromObjectWithList) {
  EXPECT_EQ("{\"a\":[1,2,3],\"b\":[4,5,6]}", to_json(ObjectWithLists({1, 2, 3}, {4, 5, 6})));
}

TEST(from_json, toObjectWithList) {
  ObjectWithLists result;
  from_json("{ \"a\" : [1, 2, 3], \"b\" : [4, 5, 6] }", result);
  EXPECT_EQ(ObjectWithLists({1, 2, 3}, {4, 5, 6}), result);
}

TEST(to_json, fromListWithObjects) {
  auto l = std::list<Object>({Object(1,2), Object(3,4)});
  EXPECT_EQ("[{\"a\":1,\"b\":2},{\"a\":3,\"b\":4}]", to_json(l));
}

TEST(from_json, toListWithObjects) {
  std::list<Object> result;
  from_json("[ { \"a\" : 1, \"b\" : 2 }, { \"a\" : 3, \"b\" : 4 } ]", result);
  EXPECT_EQ(std::list<Object>({Object(1,2), Object(3,4)}), result);
}<commit_msg>Fixed spelling of included header file.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "JSON.h"

#include "gtest/gtest.h"

using namespace CoAP;

TEST(without, non_empty) {
  EXPECT_EQ("abc", __internal__::without('<', '>', "<abc>"));
}

TEST(without, empty) {
  EXPECT_EQ("", __internal__::without('<', '>', "<>"));
}

TEST(without, exception_without_opening_bracket) {
  EXPECT_THROW(__internal__::without('<', '>', "abc>"), std::runtime_error);
}

TEST(without, exception_without_closing_bracket) {
  EXPECT_THROW(__internal__::without('<', '>', "<abc"), std::runtime_error);
}

TEST(withoutCurly, non_empty) {
  EXPECT_EQ("abc", __internal__::withoutCurly("{abc}"));
}

TEST(withoutRect, non_empty) {
  EXPECT_EQ("abc", __internal__::withoutRect("[abc]"));
}

TEST(withoutQuot, non_empty) {
  EXPECT_EQ("abc", __internal__::withoutQuot("\"abc\""));
}

TEST(find_element_delimiter, simple) {
  EXPECT_EQ(1, __internal__::findListDelimiter("a,b"));
}

TEST(find_element_delimiter, nested) {
  EXPECT_EQ(5, __internal__::findListDelimiter("{a,b},c"));
}

TEST(trimmed, without_spaces) {
  EXPECT_EQ("hello", __internal__::trimmed("hello"));
}

TEST(trimmed, leading_spaces) {
  EXPECT_EQ("hello", __internal__::trimmed("   hello"));
}

TEST(trimmed, trailing_spaces) {
  EXPECT_EQ("hello", __internal__::trimmed("hello   "));
}

TEST(trimmed, one_space) {
  EXPECT_EQ("", __internal__::trimmed(" "));
}

TEST(trimmed, two_spaces) {
  EXPECT_EQ("", __internal__::trimmed(" "));
}

TEST(to_json, fromString) {
  EXPECT_EQ("\"text\"", to_json("text"));
}

TEST(from_json, toString) {
  std::string result;
  from_json(" \"text\" ", result);
  EXPECT_EQ("text", result);
}

TEST(to_json, fromStdString) {
  EXPECT_EQ("\"text\"", to_json(std::string("text")));
}

TEST(to_json, fromTrue) {
  EXPECT_EQ("true", to_json(true));
}

TEST(from_json, toTrue) {
  bool result;
  from_json("true", result);
  EXPECT_EQ(true, result);
}

TEST(to_json, fromFalse) {
  EXPECT_EQ("false", to_json(false));
}

TEST(from_json, toFalse) {
  bool result;
  from_json("false", result);
  EXPECT_EQ(false, result);
}

TEST(to_json, fromInt) {
  EXPECT_EQ("-123", to_json(-123));
}

TEST(from_json, toInt) {
  int result;
  from_json("-123", result);
  EXPECT_EQ(-123, result);
}

TEST(to_json, fromUInt) {
  EXPECT_EQ("123", to_json(123u));
}

TEST(from_json, toUInt) {
  unsigned int result;
  from_json("123", result);
  EXPECT_EQ(123, result);
}

TEST(to_json, fromDouble) {
  EXPECT_EQ("1.23", to_json(1.23));
}

TEST(to_json, fromNaturalDouble) {
  EXPECT_EQ("3", to_json(3));
}

TEST(to_json, fromNegativeDouble) {
  EXPECT_EQ("-3.141", to_json(-3.141));
}

TEST(from_json, toDouble) {
  double result;
  from_json("1.23", result);
  EXPECT_DOUBLE_EQ(1.23, result);
}

TEST(from_json, toNaturalDouble) {
  double result;
  from_json("3", result);
  EXPECT_DOUBLE_EQ(3, result);
}

TEST(from_json, toNegativeDouble) {
  double result;
  from_json("-3.141", result);
  EXPECT_DOUBLE_EQ(-3.141, result);
}

TEST(to_json, fromEmptyList) {
  EXPECT_EQ("[]", to_json(std::list<int>()));
}

TEST(from_json, toEmptyList) {
  std::list<int> result;
  from_json("[ ]", result);
  EXPECT_EQ(0, result.size());
}

TEST(to_json, fromListOfInts) {
  auto l = std::list<int>({1,2,3});
  EXPECT_EQ("[1,2,3]", to_json(l));
}

TEST(from_json, toListOfInts) {
  std::list<int> result;
  from_json("[1,2,3]", result);
  EXPECT_EQ(3, result.size());
  auto it = result.begin();
  EXPECT_EQ(1, *it++);
  EXPECT_EQ(2, *it++);
  EXPECT_EQ(3, *it++);
}

TEST(to_json, fromListOfStrings) {
  auto l = std::list<std::string>({"a", "b", "c"});
  EXPECT_EQ("[\"a\",\"b\",\"c\"]", to_json(l));
}

TEST(from_json, toListOfStrings) {
  std::list<std::string> result;
  from_json("[\"a\",\"b\",\"c\"]", result);
  EXPECT_EQ(3, result.size());
  auto it = result.begin();
  EXPECT_EQ("a", *it++);
  EXPECT_EQ("b", *it++);
  EXPECT_EQ("c", *it++);
}

namespace {
class Object {
  int a_{0};
  int b_{0};
 public:
  Object() = default;
  Object(int a, int b) : a_(a), b_(b) { }

  bool operator==(const Object& rhs) const {
    return a_ == rhs.a_
        && b_ == rhs.b_;
  }

  std::string to_json() const {
    return ::to_json("a", a_) + "," + ::to_json("b", b_);
  }

  void from_json(const std::string& j) {
    ::from_json(j, "a", a_);
    ::from_json(j, "b", b_);
  }
};

};

TEST(to_json, fromObject) {
  EXPECT_EQ("{\"a\":1,\"b\":2}", to_json(Object(1,2)));
}

TEST(from_json, toObjectOriginalOrder) {
  Object result;
  from_json("{\"a\":1,\"b\":2}", result);
  EXPECT_EQ(Object(1, 2), result);
}

TEST(from_json, toObjectDifferentOrder) {
  Object result;
  from_json("{\"b\":2,\"a\":1}", result);
  EXPECT_EQ(Object(1, 2), result);
}

namespace {
class ObjectObject {
  Object obj_;
 public:
  ObjectObject() = default;
  ObjectObject(int a, int b) : obj_(a, b) { }

  bool operator==(const ObjectObject& rhs) const {
    return obj_ == rhs.obj_;
  }

  std::string to_json() const {
    return ::to_json("obj", obj_);
  }

  void from_json(const std::string& j) {
    ::from_json(j, "obj", obj_);
  }
};
}

TEST(to_json, fromObjectWithObject) {
  EXPECT_EQ("{\"obj\":{\"a\":1,\"b\":2}}", to_json(ObjectObject(1,2)));
}

TEST(from_json, toObjectWithObject) {
  ObjectObject result;
  from_json("{\"obj\":{\"a\":1,\"b\":2}}", result);
  EXPECT_EQ(ObjectObject(1,2), result);
}

namespace {
class ObjectWithLists {
  std::list<int> a_;
  std::list<int> b_;
 public:
  ObjectWithLists() = default;
  ObjectWithLists(std::list<int> a, std::list<int> b) : a_(a), b_(b) { }

  bool operator==(const ObjectWithLists& rhs) const {
    return a_ == rhs.a_
        && b_ == rhs.b_;
  }

  std::string to_json() const {
    return ::to_json("a", a_) + ","
        + ::to_json("b", b_);
  }

  void from_json(const std::string& j) {
    ::from_json(j, "a", a_);
    ::from_json(j, "b", b_);
  }
};
}

TEST(to_json, fromObjectWithList) {
  EXPECT_EQ("{\"a\":[1,2,3],\"b\":[4,5,6]}", to_json(ObjectWithLists({1, 2, 3}, {4, 5, 6})));
}

TEST(from_json, toObjectWithList) {
  ObjectWithLists result;
  from_json("{ \"a\" : [1, 2, 3], \"b\" : [4, 5, 6] }", result);
  EXPECT_EQ(ObjectWithLists({1, 2, 3}, {4, 5, 6}), result);
}

TEST(to_json, fromListWithObjects) {
  auto l = std::list<Object>({Object(1,2), Object(3,4)});
  EXPECT_EQ("[{\"a\":1,\"b\":2},{\"a\":3,\"b\":4}]", to_json(l));
}

TEST(from_json, toListWithObjects) {
  std::list<Object> result;
  from_json("[ { \"a\" : 1, \"b\" : 2 }, { \"a\" : 3, \"b\" : 4 } ]", result);
  EXPECT_EQ(std::list<Object>({Object(1,2), Object(3,4)}), result);
}<|endoftext|>


<commit_before>#include <iostream>
#include "classes/Filter.cpp"
#include "classes/Matrix.cpp"
#include "classes/BlockDiagMatrix.cpp"
#include "classes/Buffer.cpp"

using namespace std;

int main () {
	int x = 60;

	Matrix a(x,x);
	a.identity();

	cout << a.toString() << endl << endl;

	Matrix b(x,1);
	b.fill();

	Matrix c(1,x);
	c.fill();

	cout << c.multiply(a).toString();

	BlockDiagMatrix z(10,10,2);

	return 0;
}
<commit_msg>BlockMAtrix tests<commit_after>#include <iostream>
#include "classes/Filter.cpp"
#include "classes/Matrix.cpp"
#include "classes/BlockDiagMatrix.cpp"
#include "classes/Buffer.cpp"

using namespace std;

int main () {
	int x = 6;

	BlockDiagMatrix a;
	a.resize(x,x,2);

	a.identity();

	BlockDiagMatrix b(x,x,2);
	b.fill();

	cout << a.toString() << endl;
	cout << b.toString() << endl;
	cout << a.multiply(b).toString();

	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009 Marc Boris Duerner, Tommi Maekitalo
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "tcpsocketimpl.h"
#include "tcpserverimpl.h"
#include "addrinfo.h"
#include "cxxtools/log.h"
#include "cxxtools/tcpserver.h"
#include "cxxtools/systemerror.h"

log_define("cxxtools.net.tcp")

namespace cxxtools {

namespace net {

TcpSocketImpl::TcpSocketImpl()
: _fd(-1)
{
}

TcpSocketImpl::~TcpSocketImpl()
{
}

void TcpSocketImpl::create(int domain, int type, int protocol)
{
    log_debug("create socket");
    _fd = ::socket(domain, type, protocol);
    if (_fd < 0)
      throw SystemError("socket");
}

void TcpSocketImpl::close()
{
  if (_fd >= 0)
  {
    log_debug("close socket");
    ::close(_fd);
    _fd = -1;
  }
}

void TcpSocketImpl::connect(const std::string& ipaddr, unsigned short int port)
{
    log_debug("connect to " << ipaddr << " port " << port);

    Addrinfo ai(ipaddr, port);

    log_debug("do connect");
    for (Addrinfo::const_iterator it = ai.begin(); it != ai.end(); ++it)
    {
        try
        {
            this->create(it->ai_family, SOCK_STREAM, 0);
        }
        catch (const SystemError&)
        {
            continue;
        }

        if (::connect(this->fd(), it->ai_addr, it->ai_addrlen) == 0)
        {
            // save our information
            memmove(&_peeraddr, it->ai_addr, it->ai_addrlen);
            return;
        }

        // TODO add timeout handling
        //if (errno == EINPROGRESS && getTimeout() > 0)
        {
            //poll(POLLOUT);

            int sockerr;
            socklen_t optlen = sizeof(sockerr);
            if (::getsockopt(this->fd(), SOL_SOCKET, SO_ERROR, &sockerr, &optlen) != 0)
            {
                this->close();
                throw SystemError("getsockopt");
            }

            if(sockerr != 0)
            {
                this->close();
                throw SystemError(sockerr, "connect");
            }

            // save our information
            memmove(&_peeraddr, it->ai_addr, it->ai_addrlen);
            return;
        }
    }

    throw SystemError("connect");
}

void TcpSocketImpl::accept(TcpServer& server)
{
    socklen_t peeraddr_len = sizeof(_peeraddr);

    log_debug( "accept " << server.impl().fd() );
    _fd = ::accept(server.impl().fd(), reinterpret_cast <struct sockaddr*>(&_peeraddr), &peeraddr_len);
    if( _fd < 0 )
      throw SystemError("accept");

    //TODO ECONNABORTED EINTR EPERM

    log_debug( "accepted " << server.impl().fd() << " => " << _fd );
}

} // namespace net

} // namespace cxxtools
<commit_msg>add missing header<commit_after>/*
 * Copyright (C) 2009 Marc Boris Duerner, Tommi Maekitalo
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "tcpsocketimpl.h"
#include "tcpserverimpl.h"
#include "addrinfo.h"
#include "cxxtools/log.h"
#include "cxxtools/tcpserver.h"
#include "cxxtools/systemerror.h"
#include <string.h>

log_define("cxxtools.net.tcp")

namespace cxxtools {

namespace net {

TcpSocketImpl::TcpSocketImpl()
: _fd(-1)
{
}

TcpSocketImpl::~TcpSocketImpl()
{
}

void TcpSocketImpl::create(int domain, int type, int protocol)
{
    log_debug("create socket");
    _fd = ::socket(domain, type, protocol);
    if (_fd < 0)
      throw SystemError("socket");
}

void TcpSocketImpl::close()
{
  if (_fd >= 0)
  {
    log_debug("close socket");
    ::close(_fd);
    _fd = -1;
  }
}

void TcpSocketImpl::connect(const std::string& ipaddr, unsigned short int port)
{
    log_debug("connect to " << ipaddr << " port " << port);

    Addrinfo ai(ipaddr, port);

    log_debug("do connect");
    for (Addrinfo::const_iterator it = ai.begin(); it != ai.end(); ++it)
    {
        try
        {
            this->create(it->ai_family, SOCK_STREAM, 0);
        }
        catch (const SystemError&)
        {
            continue;
        }

        if (::connect(this->fd(), it->ai_addr, it->ai_addrlen) == 0)
        {
            // save our information
            memmove(&_peeraddr, it->ai_addr, it->ai_addrlen);
            return;
        }

        // TODO add timeout handling
        //if (errno == EINPROGRESS && getTimeout() > 0)
        {
            //poll(POLLOUT);

            int sockerr;
            socklen_t optlen = sizeof(sockerr);
            if (::getsockopt(this->fd(), SOL_SOCKET, SO_ERROR, &sockerr, &optlen) != 0)
            {
                this->close();
                throw SystemError("getsockopt");
            }

            if(sockerr != 0)
            {
                this->close();
                throw SystemError(sockerr, "connect");
            }

            // save our information
            memmove(&_peeraddr, it->ai_addr, it->ai_addrlen);
            return;
        }
    }

    throw SystemError("connect");
}

void TcpSocketImpl::accept(TcpServer& server)
{
    socklen_t peeraddr_len = sizeof(_peeraddr);

    log_debug( "accept " << server.impl().fd() );
    _fd = ::accept(server.impl().fd(), reinterpret_cast <struct sockaddr*>(&_peeraddr), &peeraddr_len);
    if( _fd < 0 )
      throw SystemError("accept");

    //TODO ECONNABORTED EINTR EPERM

    log_debug( "accepted " << server.impl().fd() << " => " << _fd );
}

} // namespace net

} // namespace cxxtools
<|endoftext|>


<commit_before>/*
 The MIT License (MIT)

 Copyright (c) [2016] [BTC.COM]

 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.
 */
#pragma once

#include <string>
#include <map>
#include <set>
#include <atomic>
#include <thread>

#include <glog/logging.h>

#include "Kafka.h"
#include "MySQLConnection.hpp"
#include "utilities_js.hpp"
#include "utils.hpp"

using namespace std;

class WorkerUpdate {
public:
    const size_t FLUSH_SIZE = 1;
    const time_t FIX_GROUPID_INTERVAL = 60;

    WorkerUpdate(
        string consumeBrokers, string consumeTopic, string consumeGroupId,
        const MysqlConnectInfo &mysqlInfo
    )
        : running_(false), messageNumber_(0), lastMessageTime_{0}
        , consumeBrokers_(consumeBrokers), consumeTopic_(consumeTopic), consumeGroupId_(consumeGroupId)
        , consumer_(consumeBrokers_.c_str(), consumeTopic_.c_str(), 0/* patition */, consumeGroupId_.c_str())
        , mysqlInfo_(mysqlInfo)
    {
    }

    bool init() {
        LOG(INFO) << "setup kafka consumer...";
        if (!consumer_.setup()) {
            LOG(ERROR) << "setup kafka consumer fail";
            return false;
        }

        mysqlConn_ = make_shared<MySQLConnection>(mysqlInfo_);
        if (!mysqlConn_->ping()) {
            LOG(INFO) << "common events db ping failure";
            return false;
        }

        return true;
    }

    void run() {
        const int32_t kTimeoutMs = 1000;
        running_ = true;

        LOG(INFO) << "waiting kafka messages...";
        while (running_) {
            //
            // consume message
            //
            rd_kafka_message_t *rkmessage;
            rkmessage = consumer_.consumer(kTimeoutMs);

            // timeout, most of time it's not nullptr and set an error:
            //          rkmessage->err == RD_KAFKA_RESP_ERR__PARTITION_EOF
            if (rkmessage == nullptr) {
                continue;
            }

            // check error
            if (rkmessage->err) {
                if (rkmessage->err == RD_KAFKA_RESP_ERR__PARTITION_EOF) {
                    // Reached the end of the topic+partition queue on the broker.
                    // Not really an error.
                    //      LOG(INFO) << "consumer reached end of " << rd_kafka_topic_name(rkmessage->rkt)
                    //      << "[" << rkmessage->partition << "] "
                    //      << " message queue at offset " << rkmessage->offset;
                    // acturlly
                    rd_kafka_message_destroy(rkmessage);  /* Return message to rdkafka */
                    continue;
                }

                LOG(ERROR) << "consume error for topic " << rd_kafka_topic_name(rkmessage->rkt)
                           << "[" << rkmessage->partition << "] offset " << rkmessage->offset
                           << ": " << rd_kafka_message_errstr(rkmessage);

                if (rkmessage->err == RD_KAFKA_RESP_ERR__UNKNOWN_PARTITION ||
                    rkmessage->err == RD_KAFKA_RESP_ERR__UNKNOWN_TOPIC) {
                    LOG(FATAL) << "consume fatal";
                    running_ = false;
                    rd_kafka_message_destroy(rkmessage);  /* Return message to rdkafka */
                    continue;
                }

                rd_kafka_message_destroy(rkmessage);  /* Return message to rdkafka */
                continue;
            }

            DLOG(INFO) << "a new message, size: " << rkmessage->len;

            // repeat a message
            bool success = handleMessage(rkmessage);
            if (success) {
                messageNumber_++;
            }

            rd_kafka_message_destroy(rkmessage);  /* Return message to rdkafka */
        }

        LOG(INFO) << "kafka consumer stopped";
    }

    void stop() {
        LOG(INFO) << "stopping kafka consume...";
        running_ = false;
    }

    bool isRunning() {
        return running_;
    }

    size_t getMessageNumber() {
        return messageNumber_;
    }

    void resetMessageNumber() {
        messageNumber_ = 0;
    }

    void runMessageNumberDisplayThread(time_t interval) {
        std::thread t([this, interval] () {
            this->resetMessageNumber();
            while (this->isRunning()) {
                sleep(interval);
                size_t num = this->getMessageNumber();
                this->resetMessageNumber();
                displayMessageNumber(num, interval);
            }
        });
        t.detach();
    }

protected:
    bool handleMessage(rd_kafka_message_t *rkmessage) {
        // check error
        if (rkmessage->err) {
            if (rkmessage->err == RD_KAFKA_RESP_ERR__PARTITION_EOF) {
            // Reached the end of the topic+partition queue on the broker.
            // Not really an error.
            //      LOG(INFO) << "consumer reached end of " << rd_kafka_topic_name(rkmessage->rkt)
            //      << "[" << rkmessage->partition << "] "
            //      << " message queue at offset " << rkmessage->offset;
            // acturlly
            return false;
            }

            LOG(ERROR) << "consume error for topic " << rd_kafka_topic_name(rkmessage->rkt)
            << "[" << rkmessage->partition << "] offset " << rkmessage->offset
            << ": " << rd_kafka_message_errstr(rkmessage);

            if (rkmessage->err == RD_KAFKA_RESP_ERR__UNKNOWN_PARTITION ||
                rkmessage->err == RD_KAFKA_RESP_ERR__UNKNOWN_TOPIC) {
            LOG(FATAL) << "consume fatal";
            }
            return false;
        }

        const char *message = (const char*)rkmessage->payload;
        DLOG(INFO) << "A New Common Event: " << string(message, rkmessage->len);

        JsonNode r;
        if (!JsonNode::parse(message, message + rkmessage->len, r)) {
            LOG(ERROR) << "decode common event failure";
            return false;
        }

        // check fields
        if (r["type"].type()    != Utilities::JS::type::Str ||
            r["content"].type() != Utilities::JS::type::Obj ||
            r["created_at"].type() != Utilities::JS::type::Str) {
            LOG(ERROR) << "common event missing some fields";
            return false;
        }

        string lastMessageTime = r["created_at"].str();
        lastMessageTime.resize(19);
        memcpy(lastMessageTime_, lastMessageTime.c_str(), 20);

        // update worker status
        if (r["type"].str() == "worker_update") {
            // check fields
            if (r["content"]["user_id"].type()     != Utilities::JS::type::Int ||
                r["content"]["worker_id"].type()   != Utilities::JS::type::Int ||
                r["content"]["worker_name"].type() != Utilities::JS::type::Str ||
                r["content"]["miner_agent"].type() != Utilities::JS::type::Str) {
                LOG(ERROR) << "common event `worker_update` missing some fields";
                return false;
            }

            int32_t userId    = r["content"]["user_id"].int32();
            int64_t workerId  = r["content"]["worker_id"].int64();
            string workerName = filterWorkerName(r["content"]["worker_name"].str());
            string minerAgent = filterWorkerName(r["content"]["miner_agent"].str());

            updateWorkerStatusToDB(userId, workerId, workerName.c_str(), minerAgent.c_str());
            return true;
        }

        // There is no worker_id in miner_connect event for legacy branch.
        // TODO: compute worker_id for miner_connect event
        /*if (r["type"].str() == "miner_connect") {
            // check fields
            if (r["content"]["user_id"].type()     != Utilities::JS::type::Int ||
                r["content"]["worker_id"].type()   != Utilities::JS::type::Int ||
                r["content"]["worker_name"].type() != Utilities::JS::type::Str ||
                r["content"]["client_agent"].type() != Utilities::JS::type::Str) {
                LOG(ERROR) << "common event `miner_connect` missing some fields";
                return false;
            }

            int32_t userId    = r["content"]["user_id"].int32();
            int64_t workerId  = r["content"]["worker_id"].int64();
            string workerName = filterWorkerName(r["content"]["worker_name"].str());
            string minerAgent = filterWorkerName(r["content"]["client_agent"].str());

            updateWorkerStatusToDB(userId, workerId, workerName.c_str(), minerAgent.c_str());
            return true;
        }*/

        return false;
    }

    string sql_;
    time_t lastFixGroupIdTime_ = 0;

    bool updateWorkerStatusToDB(
        const int32_t userId, const int64_t workerId,
        const char *workerName, const char *minerAgent) {
        MySQLResult res;
        time_t now = time(nullptr);
        const string nowStr = date("%F %T", now);

        const string sqlBegin =
            "INSERT INTO `mining_workers`(`puid`,`worker_id`,"
            " `group_id`,`worker_name`,`miner_agent`,"
            " `created_at`,`updated_at`) VALUES";
        const string sqlEnd =
            " ON DUPLICATE KEY UPDATE "
            " `worker_name`= VALUES(`worker_name`),"
            " `miner_agent`= VALUES(`miner_agent`),"
            " `updated_at`= VALUES(`updated_at`)";

		static map<int32_t, set<int64_t>> workerCache;

		if (workerCache[userId].find(workerId) != workerCache[userId].end()) {
			return true;
		}

        string sqlValues = StringFormat(
            "(%d,%" PRId64",%d,'%s','%s','%s','%s')",
            userId, workerId,
            userId * -1,  // default group id
            workerName, minerAgent,
            nowStr.c_str(), nowStr.c_str());

        sql_ += sql_.empty() ? sqlBegin : ", ";
        sql_ += sqlValues;

		workerCache[userId].insert(workerId);

        if (sql_.size() < FLUSH_SIZE) {
            return true;
        }

        sql_ += sqlEnd;

        if (mysqlConn_->execute(sql_) == false) {
            LOG(ERROR) << "insert worker name failure";

            // try to reconnect mysql, so last update may success
            if (!mysqlConn_->reconnect()) {
                LOG(ERROR) << "updateWorkerStatusToDB: can't connect to pool DB";
            }

            sql_.clear();
            return false;
        }

        if (now - lastFixGroupIdTime_ > FIX_GROUPID_INTERVAL) {
            sql_ = "UPDATE `mining_workers` SET `group_id`=-`puid`"
                " WHERE `group_id`=0 AND `last_share_time` > CURRENT_TIMESTAMP()-900";

            if (mysqlConn_->execute(sql_)) {
                LOG(ERROR) << "fix group_id success";
                lastFixGroupIdTime_ = now;
            } else {
                LOG(ERROR) << "fix group_id failure";
            }
        }

        sql_.clear();
        return true;
    }

    void displayMessageNumber(size_t messageNumber, time_t time) {
        LOG(INFO) << "Handled " << messageNumber << " messages in " << time << " seconds, last message time: " << lastMessageTime_;
    }

    std::atomic<bool> running_;
    size_t messageNumber_; // don't need thread safe (for logs only)
    char lastMessageTime_[20]; // xxxx-xx-xx xx:xx:xx

    string consumeBrokers_;
    string consumeTopic_;
    string consumeGroupId_;
    KafkaHighLevelConsumer consumer_;

    MysqlConnectInfo mysqlInfo_;
    shared_ptr<MySQLConnection> mysqlConn_;
};
<commit_msg>worker_update: clear local cache after fix group_id.<commit_after>/*
 The MIT License (MIT)

 Copyright (c) [2016] [BTC.COM]

 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.
 */
#pragma once

#include <string>
#include <map>
#include <set>
#include <atomic>
#include <thread>

#include <glog/logging.h>

#include "Kafka.h"
#include "MySQLConnection.hpp"
#include "utilities_js.hpp"
#include "utils.hpp"

using namespace std;

class WorkerUpdate {
public:
    const size_t FLUSH_SIZE = 1;
    const time_t FIX_GROUPID_INTERVAL = 60;

    WorkerUpdate(
        string consumeBrokers, string consumeTopic, string consumeGroupId,
        const MysqlConnectInfo &mysqlInfo
    )
        : running_(false), messageNumber_(0), lastMessageTime_{0}
        , consumeBrokers_(consumeBrokers), consumeTopic_(consumeTopic), consumeGroupId_(consumeGroupId)
        , consumer_(consumeBrokers_.c_str(), consumeTopic_.c_str(), 0/* patition */, consumeGroupId_.c_str())
        , mysqlInfo_(mysqlInfo)
    {
    }

    bool init() {
        LOG(INFO) << "setup kafka consumer...";
        if (!consumer_.setup()) {
            LOG(ERROR) << "setup kafka consumer fail";
            return false;
        }

        mysqlConn_ = make_shared<MySQLConnection>(mysqlInfo_);
        if (!mysqlConn_->ping()) {
            LOG(INFO) << "common events db ping failure";
            return false;
        }

        return true;
    }

    void run() {
        const int32_t kTimeoutMs = 1000;
        running_ = true;

        LOG(INFO) << "waiting kafka messages...";
        while (running_) {
            //
            // consume message
            //
            rd_kafka_message_t *rkmessage;
            rkmessage = consumer_.consumer(kTimeoutMs);

            // timeout, most of time it's not nullptr and set an error:
            //          rkmessage->err == RD_KAFKA_RESP_ERR__PARTITION_EOF
            if (rkmessage == nullptr) {
                continue;
            }

            // check error
            if (rkmessage->err) {
                if (rkmessage->err == RD_KAFKA_RESP_ERR__PARTITION_EOF) {
                    // Reached the end of the topic+partition queue on the broker.
                    // Not really an error.
                    //      LOG(INFO) << "consumer reached end of " << rd_kafka_topic_name(rkmessage->rkt)
                    //      << "[" << rkmessage->partition << "] "
                    //      << " message queue at offset " << rkmessage->offset;
                    // acturlly
                    rd_kafka_message_destroy(rkmessage);  /* Return message to rdkafka */
                    continue;
                }

                LOG(ERROR) << "consume error for topic " << rd_kafka_topic_name(rkmessage->rkt)
                           << "[" << rkmessage->partition << "] offset " << rkmessage->offset
                           << ": " << rd_kafka_message_errstr(rkmessage);

                if (rkmessage->err == RD_KAFKA_RESP_ERR__UNKNOWN_PARTITION ||
                    rkmessage->err == RD_KAFKA_RESP_ERR__UNKNOWN_TOPIC) {
                    LOG(FATAL) << "consume fatal";
                    running_ = false;
                    rd_kafka_message_destroy(rkmessage);  /* Return message to rdkafka */
                    continue;
                }

                rd_kafka_message_destroy(rkmessage);  /* Return message to rdkafka */
                continue;
            }

            DLOG(INFO) << "a new message, size: " << rkmessage->len;

            // repeat a message
            bool success = handleMessage(rkmessage);
            if (success) {
                messageNumber_++;
            }

            rd_kafka_message_destroy(rkmessage);  /* Return message to rdkafka */
        }

        LOG(INFO) << "kafka consumer stopped";
    }

    void stop() {
        LOG(INFO) << "stopping kafka consume...";
        running_ = false;
    }

    bool isRunning() {
        return running_;
    }

    size_t getMessageNumber() {
        return messageNumber_;
    }

    void resetMessageNumber() {
        messageNumber_ = 0;
    }

    void runMessageNumberDisplayThread(time_t interval) {
        std::thread t([this, interval] () {
            this->resetMessageNumber();
            while (this->isRunning()) {
                sleep(interval);
                size_t num = this->getMessageNumber();
                this->resetMessageNumber();
                displayMessageNumber(num, interval);
            }
        });
        t.detach();
    }

protected:
    bool handleMessage(rd_kafka_message_t *rkmessage) {
        // check error
        if (rkmessage->err) {
            if (rkmessage->err == RD_KAFKA_RESP_ERR__PARTITION_EOF) {
            // Reached the end of the topic+partition queue on the broker.
            // Not really an error.
            //      LOG(INFO) << "consumer reached end of " << rd_kafka_topic_name(rkmessage->rkt)
            //      << "[" << rkmessage->partition << "] "
            //      << " message queue at offset " << rkmessage->offset;
            // acturlly
            return false;
            }

            LOG(ERROR) << "consume error for topic " << rd_kafka_topic_name(rkmessage->rkt)
            << "[" << rkmessage->partition << "] offset " << rkmessage->offset
            << ": " << rd_kafka_message_errstr(rkmessage);

            if (rkmessage->err == RD_KAFKA_RESP_ERR__UNKNOWN_PARTITION ||
                rkmessage->err == RD_KAFKA_RESP_ERR__UNKNOWN_TOPIC) {
            LOG(FATAL) << "consume fatal";
            }
            return false;
        }

        const char *message = (const char*)rkmessage->payload;
        DLOG(INFO) << "A New Common Event: " << string(message, rkmessage->len);

        JsonNode r;
        if (!JsonNode::parse(message, message + rkmessage->len, r)) {
            LOG(ERROR) << "decode common event failure";
            return false;
        }

        // check fields
        if (r["type"].type()    != Utilities::JS::type::Str ||
            r["content"].type() != Utilities::JS::type::Obj ||
            r["created_at"].type() != Utilities::JS::type::Str) {
            LOG(ERROR) << "common event missing some fields";
            return false;
        }

        string lastMessageTime = r["created_at"].str();
        lastMessageTime.resize(19);
        memcpy(lastMessageTime_, lastMessageTime.c_str(), 20);

        // update worker status
        if (r["type"].str() == "worker_update") {
            // check fields
            if (r["content"]["user_id"].type()     != Utilities::JS::type::Int ||
                r["content"]["worker_id"].type()   != Utilities::JS::type::Int ||
                r["content"]["worker_name"].type() != Utilities::JS::type::Str ||
                r["content"]["miner_agent"].type() != Utilities::JS::type::Str) {
                LOG(ERROR) << "common event `worker_update` missing some fields";
                return false;
            }

            int32_t userId    = r["content"]["user_id"].int32();
            int64_t workerId  = r["content"]["worker_id"].int64();
            string workerName = filterWorkerName(r["content"]["worker_name"].str());
            string minerAgent = filterWorkerName(r["content"]["miner_agent"].str());

            updateWorkerStatusToDB(userId, workerId, workerName.c_str(), minerAgent.c_str());
            return true;
        }

        // There is no worker_id in miner_connect event for legacy branch.
        // TODO: compute worker_id for miner_connect event
        /*if (r["type"].str() == "miner_connect") {
            // check fields
            if (r["content"]["user_id"].type()     != Utilities::JS::type::Int ||
                r["content"]["worker_id"].type()   != Utilities::JS::type::Int ||
                r["content"]["worker_name"].type() != Utilities::JS::type::Str ||
                r["content"]["client_agent"].type() != Utilities::JS::type::Str) {
                LOG(ERROR) << "common event `miner_connect` missing some fields";
                return false;
            }

            int32_t userId    = r["content"]["user_id"].int32();
            int64_t workerId  = r["content"]["worker_id"].int64();
            string workerName = filterWorkerName(r["content"]["worker_name"].str());
            string minerAgent = filterWorkerName(r["content"]["client_agent"].str());

            updateWorkerStatusToDB(userId, workerId, workerName.c_str(), minerAgent.c_str());
            return true;
        }*/

        return false;
    }

    string sql_;
    time_t lastFixGroupIdTime_ = 0;

    bool updateWorkerStatusToDB(
        const int32_t userId, const int64_t workerId,
        const char *workerName, const char *minerAgent) {
        MySQLResult res;
        time_t now = time(nullptr);
        const string nowStr = date("%F %T", now);

        const string sqlBegin =
            "INSERT INTO `mining_workers`(`puid`,`worker_id`,"
            " `group_id`,`worker_name`,`miner_agent`,"
            " `created_at`,`updated_at`) VALUES";
        const string sqlEnd =
            " ON DUPLICATE KEY UPDATE "
            " `worker_name`= VALUES(`worker_name`),"
            " `miner_agent`= VALUES(`miner_agent`),"
            " `updated_at`= VALUES(`updated_at`)";

		static map<int32_t, set<int64_t>> workerCache;

		if (workerCache[userId].find(workerId) != workerCache[userId].end()) {
			return true;
		}

        string sqlValues = StringFormat(
            "(%d,%" PRId64",%d,'%s','%s','%s','%s')",
            userId, workerId,
            userId * -1,  // default group id
            workerName, minerAgent,
            nowStr.c_str(), nowStr.c_str());

        sql_ += sql_.empty() ? sqlBegin : ", ";
        sql_ += sqlValues;

		workerCache[userId].insert(workerId);

        if (sql_.size() < FLUSH_SIZE) {
            return true;
        }

        sql_ += sqlEnd;

        if (mysqlConn_->execute(sql_) == false) {
            LOG(ERROR) << "insert worker name failure";

            // try to reconnect mysql, so last update may success
            if (!mysqlConn_->reconnect()) {
                LOG(ERROR) << "updateWorkerStatusToDB: can't connect to pool DB";
            }

            sql_.clear();
            return false;
        }

        if (now - lastFixGroupIdTime_ > FIX_GROUPID_INTERVAL) {
            sql_ = "UPDATE `mining_workers` SET `group_id`=-`puid`"
                " WHERE `group_id`=0 AND `last_share_time` > CURRENT_TIMESTAMP()-900";

            if (mysqlConn_->execute(sql_)) {
                LOG(ERROR) << "fix group_id success";
                workerCache.clear();
                lastFixGroupIdTime_ = now;
            } else {
                LOG(ERROR) << "fix group_id failure";
            }
        }

        sql_.clear();
        return true;
    }

    void displayMessageNumber(size_t messageNumber, time_t time) {
        LOG(INFO) << "Handled " << messageNumber << " messages in " << time << " seconds, last message time: " << lastMessageTime_;
    }

    std::atomic<bool> running_;
    size_t messageNumber_; // don't need thread safe (for logs only)
    char lastMessageTime_[20]; // xxxx-xx-xx xx:xx:xx

    string consumeBrokers_;
    string consumeTopic_;
    string consumeGroupId_;
    KafkaHighLevelConsumer consumer_;

    MysqlConnectInfo mysqlInfo_;
    shared_ptr<MySQLConnection> mysqlConn_;
};
<|endoftext|>


<commit_before>#include <QApplication>
#include <QLineEdit>
#include <QCheckBox>
#include <QDebug>

#include <QTabFormWidget>

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  QTabFormWidget* settingsWidget = new QTabFormWidget(0);
  settingsWidget->addWidget("Menu A\\/B/A/Field A1",new QLineEdit(),LabelPolicy::Empty);
  settingsWidget->addWidget("Menu A\\/B/B/Field B1",new QLineEdit(),LabelPolicy::Show);
  settingsWidget->addWidget("Menu A\\/B/B/Field B2",new QCheckBox("Field B2"),LabelPolicy::Empty);
  settingsWidget->addWidget("Menu C/Field C1",new QLineEdit(),LabelPolicy::None);
  settingsWidget->addWidget("Menu C/Field C2",new QLineEdit(),LabelPolicy::Show);
  settingsWidget->addWidget("Menu C/Field C3",new QLineEdit(),LabelPolicy::NewLine);
  settingsWidget->show();

  qDebug() << settingsWidget->getWidget<QLineEdit>("Menu C/Field B3");
  return a.exec();
}
<commit_msg>test commit<commit_after>#include <QApplication>
#include <QLineEdit>
#include <QCheckBox>
#include <QDebug>

#include <QTabFormWidget>

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  QTabFormWidget* settingsWidget = new QTabFormWidget(0);
  settingsWidget->addWidget("Menu A\\/B/A/Field A1",new QLineEdit(),LabelPolicy::Empty);
  settingsWidget->addWidget("Menu A\\/B/B/Field B1",new QLineEdit(),LabelPolicy::Show);
  settingsWidget->addWidget("Menu A\\/B/B/Field B2",new QCheckBox("Field B2"),LabelPolicy::Empty);
  settingsWidget->addWidget("Menu C/Field C1",new QLineEdit(),LabelPolicy::None);
  settingsWidget->addWidget("Menu C/Field C2",new QLineEdit(),LabelPolicy::Show);
  settingsWidget->addWidget("Menu C/Field C3",new QLineEdit(),LabelPolicy::NewLine);
  settingsWidget->show();

  qDebug() << settingsWidget->getWidget<QLineEdit>("Menu C/Field B3");
  return a.exec();
}
<|endoftext|>


<commit_before>#include <aery32/all.h>
#include "board.h"

#define LED			AVR32_PIN_PC04
#define ADC_PINMASK_ALLCHAN	(0xff << 21)

using namespace aery;
using namespace boad;

int main(void)
{
	uint16_t result; /* conversion result in bits */
	double volt;     /* conversion in volts */

	/*
	 * Put your application initialization sequence here. The default
	 * board initializer defines all pins as input and sets the CPU clock
	 * speed to 66 MHz.
	 */
	board::init();

	gpio_init_pins(porta, ADC_PINMASK_ALLCHAN, GPIO_FUNCTION_A);

	adc_init(
		7,    /* prescal, adclk = pba_clk / (2 * (prescal+1)) */
		true, /* hires, 10-bit (false would be 8-bit) */
		0,    /* shtim, sample and hold time = (shtim + 3) / adclk */
		0     /* startup, startup time = (startup + 1) * 8 / adclk */
	);

	/* Enable ADC channel 3. That's PA24. */
	adc_enable(1 << 3);

	gpio_init_pin(LED, GPIO_OUTPUT);
	gpio_set_pin_high(LED);

	for(;;) {
		/* Put your application code here */

		adc_start_cnv();

		while (adc_isbusy(1 << 3));
		result = adc_read_cnv(3);
		volt = cnv_to_volt(result);
	}

	return 0;
}
<commit_msg>Fix typo in namespace<commit_after>#include <aery32/all.h>
#include "board.h"

#define LED			AVR32_PIN_PC04
#define ADC_PINMASK_ALLCHAN	(0xff << 21)

using namespace aery;
using namespace board;

int main(void)
{
	uint16_t result; /* conversion result in bits */
	double volt;     /* conversion in volts */

	/*
	 * Put your application initialization sequence here. The default
	 * board initializer defines all pins as input and sets the CPU clock
	 * speed to 66 MHz.
	 */
	board::init();

	gpio_init_pins(porta, ADC_PINMASK_ALLCHAN, GPIO_FUNCTION_A);

	adc_init(
		7,    /* prescal, adclk = pba_clk / (2 * (prescal+1)) */
		true, /* hires, 10-bit (false would be 8-bit) */
		0,    /* shtim, sample and hold time = (shtim + 3) / adclk */
		0     /* startup, startup time = (startup + 1) * 8 / adclk */
	);

	/* Enable ADC channel 3. That's PA24. */
	adc_enable(1 << 3);

	gpio_init_pin(LED, GPIO_OUTPUT);
	gpio_set_pin_high(LED);

	for(;;) {
		/* Put your application code here */

		adc_start_cnv();

		while (adc_isbusy(1 << 3));
		result = adc_read_cnv(3);
		volt = cnv_to_volt(result);
	}

	return 0;
}
<|endoftext|>


<commit_before>#include <QImage>
#include "raster.h"
#include "pixeliterator.h"
#include "rootdrawer.h"
#include "factory.h"
#include "abstractfactory.h"
#include "drawers/rasterimagefactory.h"
#include "drawers/attributevisualproperties.h"

#include "rastervalueimage.h"

using namespace Ilwis;
using namespace Geodrawer;

REGISTER_RASTERIMAGETYPE(RasterValueImage,itNUMERICDOMAIN);

RasterValueImage::RasterValueImage(DrawerInterface *rootDrawer, const IRasterCoverage& raster, const VisualAttribute &vattribute,const IOOptions &options) :
    RasterImage(rootDrawer,raster,vattribute, options)
{
}

RasterValueImage::~RasterValueImage()
{

}

RasterImage *RasterValueImage::create(DrawerInterface *rootDrawer, const IRasterCoverage& raster, const VisualAttribute &vattribute,const IOOptions &options)
{
    return new RasterValueImage(rootDrawer, raster, vattribute, options)    ;
}

bool RasterValueImage::prepare(int prepareType)
{
    bool resetImage = false;
    BoundingBox bb(_raster->size());
    // lines must be 32 bit alligned. an entry pixel is a byte, so everything must be 4 alligned (32 bit is 4 bytes)
    int xl = (quint32)bb.xlength() % 4 == 0 ? bb.xlength() : (((quint32)bb.xlength() / 4) + 1) * 4;
    int rest = xl - bb.xlength();
    if ( hasType(prepareType, DrawerInterface::ptRENDER)){
        std::vector<QColor> colors = _visualAttribute.colors();
        _colorTable = QVector<QRgb>(colors.size()) ;
        for(int i = 0; i < _colorTable.size(); ++i)
            _colorTable[i] = colors[i].rgba();
        resetImage = true;

    }

    if ( hasType(prepareType, DrawerInterface::ptGEOMETRY)){
        quint32 size = xl * bb.ylength();
        _pixels.resize(size);
        PixelIterator pixIter(_raster);

        SPNumericRange numrange =  _raster->datadef().range<NumericRange>();
        auto end = pixIter.end();
        quint32 position = 0;
        while(pixIter != end){
            double value = *pixIter;
            int index = value == rUNDEF ? 0 : 1 + (_colorTable.size() - 1) * (value - numrange->min()) / numrange->distance();
            _pixels[position] = index;
            ++pixIter;
            if ( pixIter.ychanged()){
                position += rest;
            }
            ++position;
        }
        resetImage = true;
    }

    if ( resetImage)   {
        const uchar *datablock = (const uchar *)_pixels.data();
        _image.reset(new QImage(datablock,xl, bb.ylength(),QImage::Format_Indexed8));
        _image->setColorTable(_colorTable);
    }
    return resetImage;

}

<commit_msg>added make imageTemp; functie is nog niet actief maar bevat stuk code voor efficienter uitrekening van het display image<commit_after>#include <QImage>
#include "raster.h"
#include "pixeliterator.h"
#include "rootdrawer.h"
#include "factory.h"
#include "abstractfactory.h"
#include "drawers/rasterimagefactory.h"
#include "drawers/attributevisualproperties.h"

#include "rastervalueimage.h"

using namespace Ilwis;
using namespace Geodrawer;

REGISTER_RASTERIMAGETYPE(RasterValueImage,itNUMERICDOMAIN);

RasterValueImage::RasterValueImage(DrawerInterface *rootDrawer, const IRasterCoverage& raster, const VisualAttribute &vattribute,const IOOptions &options) :
    RasterImage(rootDrawer,raster,vattribute, options)
{
}

RasterValueImage::~RasterValueImage()
{

}

RasterImage *RasterValueImage::create(DrawerInterface *rootDrawer, const IRasterCoverage& raster, const VisualAttribute &vattribute,const IOOptions &options)
{
    return new RasterValueImage(rootDrawer, raster, vattribute, options)    ;
}

bool RasterValueImage::prepare(int prepareType)
{
    bool resetImage = false;
    BoundingBox bb(_raster->size());
    // lines must be 32 bit alligned. an entry pixel is a byte, so everything must be 4 alligned (32 bit is 4 bytes)
    int xl = (quint32)bb.xlength() % 4 == 0 ? bb.xlength() : (((quint32)bb.xlength() / 4) + 1) * 4;
    int rest = xl - bb.xlength();
    if ( hasType(prepareType, DrawerInterface::ptRENDER)){
        std::vector<QColor> colors = _visualAttribute.colors();
        _colorTable = QVector<QRgb>(colors.size()) ;
        for(int i = 0; i < _colorTable.size(); ++i)
            _colorTable[i] = colors[i].rgba();
        resetImage = true;

    }

    if ( hasType(prepareType, DrawerInterface::ptGEOMETRY)){
        quint32 size = xl * bb.ylength();
        _pixels.resize(size);
        PixelIterator pixIter(_raster);

        SPNumericRange numrange =  _raster->datadef().range<NumericRange>();
        auto end = pixIter.end();
        quint32 position = 0;
        while(pixIter != end){
            double value = *pixIter;
            int index = value == rUNDEF ? 0 : 1 + (_colorTable.size() - 1) * (value - numrange->min()) / numrange->distance();
            _pixels[position] = index;
            ++pixIter;
            if ( pixIter.ychanged()){
                position += rest;
            }
            ++position;
        }
        resetImage = true;
    }

    if ( resetImage)   {
        const uchar *datablock = (const uchar *)_pixels.data();
        _image.reset(new QImage(datablock,xl, bb.ylength(),QImage::Format_Indexed8));
        _image->setColorTable(_colorTable);
    }
    return resetImage;

}

void RasterImage::makeImageTemp()
{
    // doesnt work, but i keep it around for later checking, should be more efficient version of makeImage()
//    BoundingBox bb(_raster->size()); // = _rootDrawer->screenGrf()->coord2Pixel(_raster->envelope());
//    Size<> pixArea = _rootDrawer->pixelAreaSize();
//    double dx = std::max(1.0,(double)bb.xlength() / pixArea.xsize());
//    double dy = std::max(1.0,(double)bb.ylength() / pixArea.ysize());
//    std::vector<double> xsteps(pixArea.xsize(),0);
//    std::vector<double> ysteps(pixArea.ysize(),0);

//    for(int x = 1; x < xsteps.size(); ++x){
//        xsteps[x] = xsteps[x-1] + dx;
//    }
//    for(int x = 1; x < xsteps.size(); ++x){
//        xsteps[x] = (int)(xsteps[x] - (int)((x - 1) * dx));

//    }
//    for(int y = 1; y < ysteps.size(); ++y){
//        ysteps[y] = ysteps[y-1] + dy;
//    }
//    for(int y = 1; y < ysteps.size(); ++y){
//        ysteps[y] = (int)(ysteps[y] - (int)((y - 1) * dy));
//    }

//     _pixels.resize(pixArea.linearSize());
//    PixelIterator pixIter(_raster);
//    int xindex = 1;
//    int yindex = 1;

//    while(yindex != ysteps.size()){
//        double value = *pixIter;
//        auto color = _visualAttribute.value2color(value);
//        _pixels[yindex * pixArea.xsize() + xindex] = color;
//        pixIter += xsteps[xindex++];
//        if ( pixIter.ychanged()){
//            pixIter = Pixel(0,pixIter.y() + ysteps[yindex++]);
//            xindex = 0;
//        }

//    }

//    const uchar *datablock = (const uchar *)_pixels.data();
//    _image.reset(new QImage(datablock,pixArea.xsize(), pixArea.ysize(),QImage::Format_RGBA8888));
}

<|endoftext|>


<commit_before>// Dijkstra algorithm is well-known algorithm for single-source shortes path problem.
// This file contains Dijkstra algorithm implementation.
//
// Copyright (c) savrus, 2014

#pragma once

#include <vector>
#include <cassert>
#include "graph.hpp"
#include "binheap.hpp"
#include "kheap.hpp"

// Data structures to implement Dijkstra-like algorithms
class BasicDijkstra {
protected:
    Graph *g;                             // graph
    KHeap<Vertex, Distance> queue;        // Dijkstra queue
    std::vector<Vertex> parent;           // parent[v] is v's parent in the shortest path tree
    std::vector<Distance> distance;       // distance[v] is distance from source to v
    std::vector<bool> is_dirty;           // is_dirty[v] is true if we touched v in current run
    std::vector<Vertex> dirty;            // list of visited vertices

    // Update vertex v: set distance to d and parent to p
    void update(Vertex v, Distance d, Vertex p = none) {
        distance[v] = d;
        parent[v] = p;
        queue.update(v, d);
        if (!is_dirty[v]) { dirty.push_back(v); is_dirty[v] = true; }
    }

    // Clear internal structures
    void clear() {
        queue.clear();
        for(size_t i = 0; i < dirty.size(); ++i) {
            parent[dirty[i]] = none;
            distance[dirty[i]] = infty;
            is_dirty[dirty[i]] = false;
        }
        dirty.clear();
        dirty.reserve(g->get_n());
    }

    BasicDijkstra(Graph &g) :
        g(&g),
        queue(g.get_n()),
        parent(g.get_n(), none),
        distance(g.get_n(), infty),
        is_dirty(g.get_n()) {}
};

// Dijkstra algorithm implementation
class Dijkstra : BasicDijkstra{
public:
    Dijkstra(Graph &g) : BasicDijkstra(g) {}

    Distance get_distance(Vertex v) { return distance[v]; }  // Distance from source to v
    Vertex get_parent(Vertex v) { return parent[v]; }        // v's parent in the shortest path tree

    // Find distances from v to all other vertices and build shortest path tree
    void run(Vertex v, bool forward = true) {
        clear();
        update(v, 0);
        while (!queue.empty()) {
            Vertex u = queue.pop();
            Distance d = distance[u];
            for (Graph::arc_iterator a = g->begin(u, forward), end = g->end(u, forward); a < end; ++a) {
                Distance dd = d + a->length;
                assert(dd > d && dd < infty);
                if (dd < distance[a->head]) update(a->head, dd, u);
            }
        }
    }
};
<commit_msg>Remove remaining binheap.hpp inclusion<commit_after>// Dijkstra algorithm is well-known algorithm for single-source shortes path problem.
// This file contains Dijkstra algorithm implementation.
//
// Copyright (c) savrus, 2014

#pragma once

#include <vector>
#include <cassert>
#include "graph.hpp"
#include "kheap.hpp"

// Data structures to implement Dijkstra-like algorithms
class BasicDijkstra {
protected:
    Graph *g;                             // graph
    KHeap<Vertex, Distance> queue;        // Dijkstra queue
    std::vector<Vertex> parent;           // parent[v] is v's parent in the shortest path tree
    std::vector<Distance> distance;       // distance[v] is distance from source to v
    std::vector<bool> is_dirty;           // is_dirty[v] is true if we touched v in current run
    std::vector<Vertex> dirty;            // list of visited vertices

    // Update vertex v: set distance to d and parent to p
    void update(Vertex v, Distance d, Vertex p = none) {
        distance[v] = d;
        parent[v] = p;
        queue.update(v, d);
        if (!is_dirty[v]) { dirty.push_back(v); is_dirty[v] = true; }
    }

    // Clear internal structures
    void clear() {
        queue.clear();
        for(size_t i = 0; i < dirty.size(); ++i) {
            parent[dirty[i]] = none;
            distance[dirty[i]] = infty;
            is_dirty[dirty[i]] = false;
        }
        dirty.clear();
        dirty.reserve(g->get_n());
    }

    BasicDijkstra(Graph &g) :
        g(&g),
        queue(g.get_n()),
        parent(g.get_n(), none),
        distance(g.get_n(), infty),
        is_dirty(g.get_n()) {}
};

// Dijkstra algorithm implementation
class Dijkstra : BasicDijkstra{
public:
    Dijkstra(Graph &g) : BasicDijkstra(g) {}

    Distance get_distance(Vertex v) { return distance[v]; }  // Distance from source to v
    Vertex get_parent(Vertex v) { return parent[v]; }        // v's parent in the shortest path tree

    // Find distances from v to all other vertices and build shortest path tree
    void run(Vertex v, bool forward = true) {
        clear();
        update(v, 0);
        while (!queue.empty()) {
            Vertex u = queue.pop();
            Distance d = distance[u];
            for (Graph::arc_iterator a = g->begin(u, forward), end = g->end(u, forward); a < end; ++a) {
                Distance dd = d + a->length;
                assert(dd > d && dd < infty);
                if (dd < distance[a->head]) update(a->head, dd, u);
            }
        }
    }
};
<|endoftext|>


<commit_before>#include "ShadingWithLightCulling.h"
#include "EngineShaderFactory.hpp"
#include "Director.h"

using namespace Device;
using namespace Core;
using namespace Rendering;
using namespace Rendering::Light;
using namespace Rendering::Buffer;
using namespace Rendering::Shader;
using namespace GPGPU::DirectCompute;
using namespace Rendering::TBDR;

ShadingWithLightCulling::ShadingWithLightCulling() :
	_offScreen(nullptr), _inputPointLightColorBuffer(nullptr),
	_inputSpotLightColorBuffer(nullptr), _inputDirectionalLightColorBuffer(nullptr),
	_inputDirectionalLightParamBuffer(nullptr), _inputDirectionalLightTransformBuffer(nullptr)
{
}

ShadingWithLightCulling::~ShadingWithLightCulling()
{
	Destory();
}

void ShadingWithLightCulling::Initialize(const Texture::DepthBuffer* opaqueDepthBuffer,
										 const Texture::RenderTexture* gbuffer_albedo_emission,
										 const Texture::RenderTexture* gbuffer_specular_metallic,
										 const Texture::RenderTexture* gbuffer_normal_roughness,
										 const Math::Size<uint>& backBufferSize, bool useDebugMode)
{
	Manager::LightManager* lightManager = Director::GetInstance()->GetCurrentScene()->GetLightManager();

	std::string filePath = "";
	{
		Factory::EngineFactory pathFind(nullptr);
		pathFind.FetchShaderFullPath(filePath, "TBDR");

		ASSERT_COND_MSG(filePath.empty() == false, "Error, File path is empty");
	}

	std::vector<ShaderMacro> macros;
	{
		if(useDebugMode)
			macros.push_back(ShaderMacro("DEBUG_MODE", ""));
	}

	LightCulling::Initialize(filePath, "TileBasedDeferredShadingCS", opaqueDepthBuffer, nullptr, &macros);

	// Input buffer
	{
		// Point Light Color
		{
			uint idx = (uint)InputBufferShaderIndex::PointLightColor;
			const ShaderResourceBuffer* srBuffer = lightManager->GetPointLightColorBufferSR();
			AddInputBufferToList(_inputPointLightColorBuffer, idx, srBuffer);
		}

		// Spot Light Color
		{
			uint idx = (uint)InputBufferShaderIndex::SpotLightColor;
			const ShaderResourceBuffer* srBuffer = lightManager->GetSpotLightColorBufferSR();
			AddInputBufferToList(_inputSpotLightColorBuffer, idx, srBuffer);
		}

		// Directional Light
		{
			// Center With DirZ
			{
				uint idx = (uint)InputBufferShaderIndex::DirectionalLightCenterWithDirZ;
				const ShaderResourceBuffer* srBuffer = lightManager->GetDirectionalLightTransformBufferSR();
				AddInputBufferToList(_inputDirectionalLightTransformBuffer, idx, srBuffer);
			}

			// Color
			{
				uint idx = (uint)InputBufferShaderIndex::DirectionalLightColor;
				const ShaderResourceBuffer* srBuffer = lightManager->GetDirectionalLightColorBufferSR();
				AddInputBufferToList(_inputSpotLightColorBuffer, idx, srBuffer);
			}

			// Param half / DirX, DirY
			{
				uint idx = (uint)InputBufferShaderIndex::DirectionalLightParam;
				const ShaderResourceBuffer* srBuffer = lightManager->GetDirectionalLightParamBufferSR();
				AddInputBufferToList(_inputDirectionalLightParamBuffer, idx, srBuffer);
			}
		}
	}

	// Input Texture
	{
		// Albedo_Emission
		{
			uint idx = (uint)InputTextureShaderIndex::GBuffer_Albedo_Emission;
			AddTextureToInputTextureList(idx, gbuffer_albedo_emission);
		}

		// Specular_Metallic
		{
			uint idx = (uint)InputTextureShaderIndex::GBuffer_Specular_Metallic;
			AddTextureToInputTextureList(idx, gbuffer_specular_metallic);
		}

		// Normal_Roughness
		{
			uint idx = (uint)InputTextureShaderIndex::GBuffer_Normal_Roughness;
			AddTextureToInputTextureList(idx, gbuffer_normal_roughness);
		}
	}

	// Offscreen
	{
		Math::Size<uint> bufferSize = backBufferSize;
		{
			const DXGI_SAMPLE_DESC& msaaDesc = Director::GetInstance()->GetDirectX()->GetMSAADesc();
			if(msaaDesc.Count > 1)
			{
				bufferSize.w *= 2;
				bufferSize.h *= 2;
			}
		}

		_offScreen = new CSRWTexture;
		_offScreen->Initialize(bufferSize, DXGI_FORMAT_R16G16B16A16_FLOAT, 0);

		ComputeShader::Output output;
		{
			output.idx		= (uint)OutputBufferShaderIndex::OutScreen;
			output.output	= _offScreen;
		}

		std::vector<ComputeShader::Output> outputs;
		outputs.push_back(output);

		SetOuputBuferToCS(outputs);
	}

	SetInputsToCS();
}

void ShadingWithLightCulling::Destory()
{
	_inputPointLightColorBuffer				= nullptr;
	_inputSpotLightColorBuffer				= nullptr;
	_inputDirectionalLightTransformBuffer	= nullptr;
	_inputDirectionalLightColorBuffer		= nullptr;
	_inputDirectionalLightParamBuffer		= nullptr;

	SAFE_DELETE(_offScreen);
	LightCulling::Destroy();
}<commit_msg>dl color 버그 수정 #89<commit_after>#include "ShadingWithLightCulling.h"
#include "EngineShaderFactory.hpp"
#include "Director.h"

using namespace Device;
using namespace Core;
using namespace Rendering;
using namespace Rendering::Light;
using namespace Rendering::Buffer;
using namespace Rendering::Shader;
using namespace GPGPU::DirectCompute;
using namespace Rendering::TBDR;

ShadingWithLightCulling::ShadingWithLightCulling() :
	_offScreen(nullptr), _inputPointLightColorBuffer(nullptr),
	_inputSpotLightColorBuffer(nullptr), _inputDirectionalLightColorBuffer(nullptr),
	_inputDirectionalLightParamBuffer(nullptr), _inputDirectionalLightTransformBuffer(nullptr)
{
}

ShadingWithLightCulling::~ShadingWithLightCulling()
{
	Destory();
}

void ShadingWithLightCulling::Initialize(const Texture::DepthBuffer* opaqueDepthBuffer,
										 const Texture::RenderTexture* gbuffer_albedo_emission,
										 const Texture::RenderTexture* gbuffer_specular_metallic,
										 const Texture::RenderTexture* gbuffer_normal_roughness,
										 const Math::Size<uint>& backBufferSize, bool useDebugMode)
{
	Manager::LightManager* lightManager = Director::GetInstance()->GetCurrentScene()->GetLightManager();

	std::string filePath = "";
	{
		Factory::EngineFactory pathFind(nullptr);
		pathFind.FetchShaderFullPath(filePath, "TBDR");

		ASSERT_COND_MSG(filePath.empty() == false, "Error, File path is empty");
	}

	std::vector<ShaderMacro> macros;
	{
		if(useDebugMode)
			macros.push_back(ShaderMacro("DEBUG_MODE", ""));
	}

	LightCulling::Initialize(filePath, "TileBasedDeferredShadingCS", opaqueDepthBuffer, nullptr, &macros);

	// Additional Input buffer
	{
		// Point Light Color
		{
			uint idx = (uint)InputBufferShaderIndex::PointLightColor;
			const ShaderResourceBuffer* srBuffer = lightManager->GetPointLightColorBufferSR();
			AddInputBufferToList(_inputPointLightColorBuffer, idx, srBuffer);
		}

		// Spot Light Color
		{
			uint idx = (uint)InputBufferShaderIndex::SpotLightColor;
			const ShaderResourceBuffer* srBuffer = lightManager->GetSpotLightColorBufferSR();
			AddInputBufferToList(_inputSpotLightColorBuffer, idx, srBuffer);
		}

		// Directional Light
		{
			// Center With DirZ
			{
				uint idx = (uint)InputBufferShaderIndex::DirectionalLightCenterWithDirZ;
				const ShaderResourceBuffer* srBuffer = lightManager->GetDirectionalLightTransformBufferSR();
				AddInputBufferToList(_inputDirectionalLightTransformBuffer, idx, srBuffer);
			}

			// Color
			{
				uint idx = (uint)InputBufferShaderIndex::DirectionalLightColor;
				const ShaderResourceBuffer* srBuffer = lightManager->GetDirectionalLightColorBufferSR();
				AddInputBufferToList(_inputDirectionalLightColorBuffer, idx, srBuffer);
			}

			// Param half / DirX, DirY
			{
				uint idx = (uint)InputBufferShaderIndex::DirectionalLightParam;
				const ShaderResourceBuffer* srBuffer = lightManager->GetDirectionalLightParamBufferSR();
				AddInputBufferToList(_inputDirectionalLightParamBuffer, idx, srBuffer);
			}
		}
	}

	// Input Texture
	{
		// Albedo_Emission
		{
			uint idx = (uint)InputTextureShaderIndex::GBuffer_Albedo_Emission;
			AddTextureToInputTextureList(idx, gbuffer_albedo_emission);
		}

		// Specular_Metallic
		{
			uint idx = (uint)InputTextureShaderIndex::GBuffer_Specular_Metallic;
			AddTextureToInputTextureList(idx, gbuffer_specular_metallic);
		}

		// Normal_Roughness
		{
			uint idx = (uint)InputTextureShaderIndex::GBuffer_Normal_Roughness;
			AddTextureToInputTextureList(idx, gbuffer_normal_roughness);
		}
	}

	// Offscreen
	{
		Math::Size<uint> bufferSize = backBufferSize;
		{
			const DXGI_SAMPLE_DESC& msaaDesc = Director::GetInstance()->GetDirectX()->GetMSAADesc();
			if(msaaDesc.Count > 1)
			{
				bufferSize.w *= 2;
				bufferSize.h *= 2;
			}
		}

		_offScreen = new CSRWTexture;
		_offScreen->Initialize(bufferSize, DXGI_FORMAT_R16G16B16A16_FLOAT, 0);

		ComputeShader::Output output;
		{
			output.idx		= (uint)OutputBufferShaderIndex::OutScreen;
			output.output	= _offScreen;
		}

		std::vector<ComputeShader::Output> outputs;
		outputs.push_back(output);

		SetOuputBuferToCS(outputs);
	}

	SetInputsToCS();
}

void ShadingWithLightCulling::Destory()
{
	_inputPointLightColorBuffer				= nullptr;
	_inputSpotLightColorBuffer				= nullptr;
	_inputDirectionalLightTransformBuffer	= nullptr;
	_inputDirectionalLightColorBuffer		= nullptr;
	_inputDirectionalLightParamBuffer		= nullptr;

	SAFE_DELETE(_offScreen);
	LightCulling::Destroy();
}<|endoftext|>


<commit_before>// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "StdAfx.h"
#include "BatchEncoder.h"
#include "utilities\Utilities.h"
#include "BatchEncoderWorkerContext.h"

CBatchEncoderWorkerContext::CBatchEncoderWorkerContext(CConfiguration* pConfig, CBatchEncoderDlg* pDlg)
    : CWorkerContext(pConfig)
{
    this->bDone = true;
    this->pDlg = pDlg;
}

CBatchEncoderWorkerContext::~CBatchEncoderWorkerContext()
{

}

void CBatchEncoderWorkerContext::Init()
{
    this->timer.Start();

    pDlg->m_Progress.SetPos(0);
}

void CBatchEncoderWorkerContext::Next(int nItemId)
{
    this->nProcessedFiles++;
    this->nErrors = (this->nProcessedFiles - 1) - this->nDoneWithoutError;

    if (this->nThreadCount == 1)
    {
        CString szText;
        szText.Format(_T("Processing item %d of %d (%d Done, %d %s)"),
            this->nProcessedFiles,
            this->nTotalFiles,
            this->nDoneWithoutError,
            this->nErrors,
            ((this->nErrors == 0) || (this->nErrors > 1)) ? _T("Errors") : _T("Error"));
        pDlg->m_StatusBar.SetText(szText, 1, 0);

        this->nLastItemId = nItemId;
        pDlg->m_LstInputItems.EnsureVisible(nItemId, FALSE);
    }
}

void CBatchEncoderWorkerContext::Done()
{
    this->timer.Stop();
    this->nErrors = this->nProcessedFiles - this->nDoneWithoutError;

    CString szText;
    szText.Format(_T("Processed %d of %d (%d Done, %d %s) in %s"),
        this->nProcessedFiles,
        this->nTotalFiles,
        this->nDoneWithoutError,
        this->nErrors,
        ((this->nErrors == 0) || (this->nErrors > 1)) ? _T("Errors") : _T("Error"),
        this->timer.Format(this->timer.ElapsedTime(), 3));
    pDlg->m_StatusBar.SetText(szText, 1, 0);

    pDlg->FinishConvert();
}

bool CBatchEncoderWorkerContext::Callback(int nItemId, int nProgress, bool bFinished, bool bError)
{
    if (bError == true)
    {
        if (pConfig->m_Options.bStopOnErrors == true)
        {
            pDlg->m_Progress.SetPos(0);
            this->bRunning = false;
        }

        return this->bRunning;
    }

    if (bFinished == false && this->bRunning == true)
    {
        nProgess[nItemId] = nProgress;

        // check previous progress if two or more passes are used to for item processing
        if (nPreviousProgess[nItemId] > nProgress)
            nPreviousProgess[nItemId] = nProgress;

        static volatile bool bSafeCheck = false;
        if (bSafeCheck == false)
        {
            bSafeCheck = true;

            if (nItemId > this->nLastItemId)
            {
                this->nLastItemId = nItemId;
                pDlg->m_LstInputItems.EnsureVisible(nItemId, FALSE);
            }

            int nTotalProgress = 0;
            int nItems = pConfig->m_Items.GetSize();
            for (int i = 0; i < nItems; i++)
            {
                if (pConfig->m_Items.GetData(i).bChecked == TRUE)
                {
                    int nItemProgress = nProgess[i];
                    int nItemPreviousProgress = nPreviousProgess[i];

                    nTotalProgress += nItemProgress;

                    if (nItemProgress > 0 && nItemProgress < 100 && nItemProgress > nItemPreviousProgress)
                    {
                        CString szProgress;
                        szProgress.Format(_T("%d%%\0"), nItemProgress);
                        pDlg->m_LstInputItems.SetItemText(i, ITEM_COLUMN_STATUS, szProgress); // Status

                        nPreviousProgess[i] = nItemProgress;
                    }
                }
            }

            int nPos = nTotalProgress / nTotalFiles;
            if (pDlg->m_Progress.GetPos() != nPos)
            {
                pDlg->m_Progress.SetPos(nPos);
            }

            bSafeCheck = false;
        }
    }

    return this->bRunning;
}

void CBatchEncoderWorkerContext::Status(int nItemId, CString szTime, CString szStatus)
{
    pDlg->m_LstInputItems.SetItemText(nItemId, ITEM_COLUMN_TIME, szTime); // Time
    pDlg->m_LstInputItems.SetItemText(nItemId, ITEM_COLUMN_STATUS, szStatus); // Status
};
<commit_msg>Added language strings support<commit_after>// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "StdAfx.h"
#include "BatchEncoder.h"
#include "utilities\Utilities.h"
#include "BatchEncoderWorkerContext.h"

const TCHAR* pszWorkerContext[] = {
    /* 00 */ _T("Error"),
    /* 01 */ _T("Errors"),
    /* 02 */ _T("Processing item %d of %d (%d Done, %d %s)"),
    /* 03 */ _T("Processed %d of %d (%d Done, %d %s) in %s")
};

CBatchEncoderWorkerContext::CBatchEncoderWorkerContext(CConfiguration* pConfig, CBatchEncoderDlg* pDlg)
    : CWorkerContext(pConfig)
{
    this->bDone = true;
    this->pDlg = pDlg;
}

CBatchEncoderWorkerContext::~CBatchEncoderWorkerContext()
{

}

void CBatchEncoderWorkerContext::Init()
{
    this->timer.Start();

    pDlg->m_Progress.SetPos(0);
}

void CBatchEncoderWorkerContext::Next(int nItemId)
{
    this->nProcessedFiles++;
    this->nErrors = (this->nProcessedFiles - 1) - this->nDoneWithoutError;

    if (this->nThreadCount == 1)
    {
        CString szText;
        szText.Format(this->GetString(0x00190003, pszWorkerContext[2]),
            this->nProcessedFiles,
            this->nTotalFiles,
            this->nDoneWithoutError,
            this->nErrors,
            ((this->nErrors == 0) || (this->nErrors > 1)) ?
            this->GetString(0x00190002, pszWorkerContext[1]) : this->GetString(0x00190001, pszWorkerContext[0]));
        pDlg->m_StatusBar.SetText(szText, 1, 0);

        this->nLastItemId = nItemId;
        pDlg->m_LstInputItems.EnsureVisible(nItemId, FALSE);
    }
}

void CBatchEncoderWorkerContext::Done()
{
    this->timer.Stop();
    this->nErrors = this->nProcessedFiles - this->nDoneWithoutError;

    CString szText;
    szText.Format(this->GetString(0x00190004, pszWorkerContext[3]),
        this->nProcessedFiles,
        this->nTotalFiles,
        this->nDoneWithoutError,
        this->nErrors,
        ((this->nErrors == 0) || (this->nErrors > 1)) ?
        this->GetString(0x00190002, pszWorkerContext[1]) : this->GetString(0x00190001, pszWorkerContext[0]),
        this->timer.Format(this->timer.ElapsedTime(), 3));
    pDlg->m_StatusBar.SetText(szText, 1, 0);

    pDlg->FinishConvert();
}

bool CBatchEncoderWorkerContext::Callback(int nItemId, int nProgress, bool bFinished, bool bError)
{
    if (bError == true)
    {
        if (pConfig->m_Options.bStopOnErrors == true)
        {
            pDlg->m_Progress.SetPos(0);
            this->bRunning = false;
        }

        return this->bRunning;
    }

    if (bFinished == false && this->bRunning == true)
    {
        nProgess[nItemId] = nProgress;

        // check previous progress if two or more passes are used to for item processing
        if (nPreviousProgess[nItemId] > nProgress)
            nPreviousProgess[nItemId] = nProgress;

        static volatile bool bSafeCheck = false;
        if (bSafeCheck == false)
        {
            bSafeCheck = true;

            if (nItemId > this->nLastItemId)
            {
                this->nLastItemId = nItemId;
                pDlg->m_LstInputItems.EnsureVisible(nItemId, FALSE);
            }

            int nTotalProgress = 0;
            int nItems = pConfig->m_Items.GetSize();
            for (int i = 0; i < nItems; i++)
            {
                if (pConfig->m_Items.GetData(i).bChecked == TRUE)
                {
                    int nItemProgress = nProgess[i];
                    int nItemPreviousProgress = nPreviousProgess[i];

                    nTotalProgress += nItemProgress;

                    if (nItemProgress > 0 && nItemProgress < 100 && nItemProgress > nItemPreviousProgress)
                    {
                        CString szProgress;
                        szProgress.Format(_T("%d%%\0"), nItemProgress);
                        pDlg->m_LstInputItems.SetItemText(i, ITEM_COLUMN_STATUS, szProgress); // Status

                        nPreviousProgess[i] = nItemProgress;
                    }
                }
            }

            int nPos = nTotalProgress / nTotalFiles;
            if (pDlg->m_Progress.GetPos() != nPos)
            {
                pDlg->m_Progress.SetPos(nPos);
            }

            bSafeCheck = false;
        }
    }

    return this->bRunning;
}

void CBatchEncoderWorkerContext::Status(int nItemId, CString szTime, CString szStatus)
{
    pDlg->m_LstInputItems.SetItemText(nItemId, ITEM_COLUMN_TIME, szTime); // Time
    pDlg->m_LstInputItems.SetItemText(nItemId, ITEM_COLUMN_STATUS, szStatus); // Status
};
<|endoftext|>