<commit_before>#include <type_traits>
#include <thread>
#include <mutex>
#include <exception>
#include <iterator>
#include <yet_another_process_library/process.hpp>

#define STRINGIFY1(x) #x
#define STRINGIFY2(x) STRINGIFY1(x)
#define LINESTR STRINGIFY2(__LINE__)

namespace yet_another_process_library
{
	template<typename T>
	bool is_set(T in, T flag)
	{
		return (in & flag) != 0;
	};

	template<typename Policy>
	class unique_handle
	{
		typename Policy::handle_type h;

	public:
		unique_handle(const unique_handle&) = delete;

		typename Policy::handle_type get() const
		{
			return h;
		}

		typename Policy::handle_type release()
		{
			typename Policy::handle_type temp = h;
			h = Policy::get_null();
			return temp;
		}

		void reset(typename Policy::handle_type new_handle)
		{
			typename Policy::handle_type old_handle = h;
			h = new_handle;
			if(!Policy::is_null(old_handle))
			{
				Policy::close(old_handle);
			}
		}

		void swap(unique_handle& other)
		{
			std::swap(this->h, other.h);
		}

		void reset()
		{
			reset(Policy::get_null());
		}

		~unique_handle()
		{
			reset();
		}

		unique_handle& operator=(unique_handle other) noexcept
		{
			this->swap(other);
			return *this;
		}

		unique_handle(unique_handle&& other) noexcept
		{
			this->h = other.h;
			other.h = Policy::get_null();
		}

		unique_handle()
		{
			h = Policy::get_null();
		}

		unique_handle(typename Policy::handle_type handle)
		{
			h = handle;
		}
	};

	void process::kill()
	{
		kill(process::ask);
	}

	process::process(
		boost::filesystem::path executable_file,
		std::function<void(boost::string_ref)> stdout_handler,
		std::function<void(boost::string_ref)> stderr_handler,
		const flags fl) :
		process(executable_file, std::vector<std::string>(), stdout_handler, stderr_handler, fl)
	{

	}
}

#if defined(_WIN32)
#include <windows.h>
static_assert(std::is_same<yet_another_process_library::process::native_handle_type, HANDLE>::value, "invalid assumption about native type");

namespace yet_another_process_library
{
	struct windows_process_handle_policy
	{
		typedef process::native_handle_type handle_type;
		static void close(handle_type handle)
		{
			::CloseHandle(handle);
		}

		static handle_type get_null()
		{
			return INVALID_HANDLE_VALUE;
		}

		static bool is_null(handle_type handle)
		{
			return handle == INVALID_HANDLE_VALUE;
		}
	};

	struct process::impl
	{
		unique_handle<windows_process_handle_policy> process_handle;
	};

	process::process(
		boost::filesystem::path executable_file,
		std::vector<std::wstring> arguments,
		std::function<void(boost::string_ref)> stdout_handler,
		std::function<void(boost::string_ref)> stderr_handler,
		const flags fl)
	{

	}

	process::process(
		boost::filesystem::path executable_file,
		std::vector<std::string> arguments,
		std::function<void(boost::string_ref)> stdout_handler,
		std::function<void(boost::string_ref)> stderr_handler,
		const flags fl)
	{

	}

	void process::write(boost::string_ref input)
	{

	}

	bool process::is_finished()
	{

	}

	boost::optional<int> process::get_exit_status()
	{

	}

	void process::kill(kill_brutality br)
	{

	}

	void process::wait()
	{

	}

	process::native_handle_type process::native_handle()
	{

	}

}
#else
#include <sys/types.h>
#include <sys/wait.h>

namespace yet_another_process_library
{
	struct unix_fd_handle_policy
	{
		typedef process::native_handle_type handle_type;
		static void close(handle_type handle)
		{
			::close(handle);
		}

		static handle_type get_null()
		{
			return -1;
		}

		static bool is_null(handle_type handle)
		{
			return handle == -1;
		}
	};

	struct pipe
	{
		unique_handle<unix_fd_handle_policy> producer;
		unique_handle<unix_fd_handle_policy> consumer;

		void reset()
		{
			producer.reset();
			consumer.reset();
		}
	};

	pipe create_pipe()
	{
		int rawp[2];
		if(::pipe(rawp) == -1)
			throw "FUCK";

		pipe p;
		p.producer = unique_handle<unix_fd_handle_policy>(rawp[0]);
		p.consumer = unique_handle<unix_fd_handle_policy>(rawp[1]);
		return p;
	}

	struct process::impl
	{
		std::mutex stdin_mutex;
		std::thread stdout_reader;
		std::thread stderr_reader;
		unique_handle<unix_fd_handle_policy> process_handle;
		unique_handle<unix_fd_handle_policy> stdin_fd;
		unique_handle<unix_fd_handle_policy> stdout_fd;
		unique_handle<unix_fd_handle_policy> stderr_fd;
		int exit_status = -1;
	};

	process::process(
		boost::filesystem::path executable_file,
		std::vector<std::wstring> arguments,
		std::function<void(boost::string_ref)> stdout_handler,
		std::function<void(boost::string_ref)> stderr_handler,
		const flags fl)
	{

	}

	process::process(
		boost::filesystem::path executable_file,
		std::vector<std::string> arguments,
		std::function<void(boost::string_ref)> stdout_handler,
		std::function<void(boost::string_ref)> stderr_handler,
		const flags fl)
	{
		pipe stdin_pipe;
		pipe stdout_pipe;
		pipe stderr_pipe;

		const bool open_stdin = !is_set(fl, stdin_closed);

		if(open_stdin)
			stdin_pipe = create_pipe();
		if(stdout_handler)
			stdout_pipe = create_pipe();
		if(stderr_handler)
			stderr_pipe = create_pipe();

		native_handle_type pid = fork();
		if(pid < 0)
			throw "FUCK";

		if(pid == 0)
		{
			if(open_stdin)
			{
				dup2(stdin_pipe.producer.get(), 0);
				stdin_pipe.consumer.reset();
			}
			if(stdout_handler)
			{
				dup2(stdout_pipe.consumer.get(), 1);
				stdout_pipe.producer.reset();
			}
			if(stderr_handler)
			{
				dup2(stderr_pipe.consumer.get(), 2);
				stderr_pipe.producer.reset();
			}

			auto close_parent_fds_above = [](int fd)
			{
				const int fd_max=sysconf(_SC_OPEN_MAX);
				for(int i = fd+1; i < fd_max; i++)
					::close(i);
			};
			close_parent_fds_above(2);

			::setpgid(0, 0);

			auto before_exec = [&]()
			{
				const bool should_suspend = is_set(fl, suspended);

				if(should_suspend)
				{
					::kill(0, SIGSTOP);
				}
			};
			before_exec();

			std::string arg0 = executable_file.stem().native();
			std::vector<char*> raw_args;
			raw_args.reserve(arguments.size()+2);
			raw_args.push_back(&arg0[0]);
			std::transform(arguments.begin(), arguments.end(), std::back_inserter(raw_args), [](std::string& s)
			{
				return &s[0];
			});
			raw_args.push_back(nullptr);
			if(is_set(fl, search_path_env))
			{
				::execvp(executable_file.native().c_str(), raw_args.data());
			}
			else
			{
				::execv(executable_file.native().c_str(), raw_args.data());
			}
			_exit(EXIT_FAILURE);
		}

		stdin_pipe.producer.reset();
		stdout_pipe.consumer.reset();
		stderr_pipe.consumer.reset();

		i.reset(new impl());
		i->stdin_fd = std::move(stdin_pipe.consumer);
		i->stdout_fd = std::move(stdout_pipe.producer);
		i->stderr_fd = std::move(stderr_pipe.producer);
		i->process_handle.reset(pid);

		auto reader = [](std::function<void(boost::string_ref)> reader, int fd)
		{
			std::vector<char> buffer(4096);
			ssize_t n;
			while(true)
			{
				n = read(fd, buffer.data(), buffer.size());
				if(n <= 0)
					break;
				reader(boost::string_ref(buffer.data(), static_cast<size_t>(n)));
			}
		};
		if(stdout_handler)
			i->stdout_reader = std::thread(reader, stdout_handler, i->stdout_fd.get());
		if(stderr_handler)
			i->stderr_reader = std::thread(reader, stderr_handler, i->stderr_fd.get());
	}

	void process::close_stdin()
	{
		std::lock_guard<std::mutex> lock(i->stdin_mutex);
		i->stdin_fd.reset();
	}

	bool process::write(boost::string_ref input)
	{
		std::lock_guard<std::mutex> lock(i->stdin_mutex);
		const int res = ::write(i->stdin_fd.get(), input.data(), input.size());
		if(res < 0)
		{
			perror(LINESTR);
			const int err = errno;
			if(err == EBADF)
				throw pipe_closed("stdin is closed");
			return false;
		}
		else if(res == 0)
			return false;
		else
			return true;
	}

	void process::suspend()
	{
		::kill(native_handle(), SIGSTOP);
	}

	void process::resume()
	{
		::kill(native_handle(), SIGCONT);
	}

	bool process::is_finished()
	{
		int exitcode = -1;
		const int res = ::waitpid(native_handle(), &exitcode, WNOHANG);
		if(res > 0)
		{
			i->exit_status = exitcode;
			return true;
		}
		else if(res == 0)
		{
			return false;
		}
		else
		{
			return true;
		}
	}

	boost::optional<int> process::get_exit_status()
	{
		if(is_finished())
		{
			return i->exit_status;
		}
		return boost::none;
	}

	void process::kill(kill_brutality br)
	{
		if(br == force)
			::kill(native_handle(), SIGTERM);
		if(br == ask)
			::kill(native_handle(), SIGKILL);
	}

	void process::wait()
	{
		waitpid(native_handle(), &i->exit_status, 0);
		i->stdin_fd.reset();
		i->stdout_fd.reset();
		i->stderr_fd.reset();
	}

	process::native_handle_type process::native_handle()
	{
		return i->process_handle.get();
	}

	process::~process()
	{
		if(!is_finished())
			std::terminate();
		if(i->stdout_reader.joinable())
			i->stdout_reader.join();
		if(i->stderr_reader.joinable())
			i->stderr_reader.join();
	}

	process::process(process&&) = default;
	process& process::operator=(process&&) = default;
}

#endif<commit_msg>removed unnecessary semicolon<commit_after>#include <type_traits>
#include <thread>
#include <mutex>
#include <exception>
#include <iterator>
#include <yet_another_process_library/process.hpp>

#define STRINGIFY1(x) #x
#define STRINGIFY2(x) STRINGIFY1(x)
#define LINESTR STRINGIFY2(__LINE__)

namespace yet_another_process_library
{
	template<typename T>
	bool is_set(T in, T flag)
	{
		return (in & flag) != 0;
	}

	template<typename Policy>
	class unique_handle
	{
		typename Policy::handle_type h;

	public:
		unique_handle(const unique_handle&) = delete;

		typename Policy::handle_type get() const
		{
			return h;
		}

		typename Policy::handle_type release()
		{
			typename Policy::handle_type temp = h;
			h = Policy::get_null();
			return temp;
		}

		void reset(typename Policy::handle_type new_handle)
		{
			typename Policy::handle_type old_handle = h;
			h = new_handle;
			if(!Policy::is_null(old_handle))
			{
				Policy::close(old_handle);
			}
		}

		void swap(unique_handle& other)
		{
			std::swap(this->h, other.h);
		}

		void reset()
		{
			reset(Policy::get_null());
		}

		~unique_handle()
		{
			reset();
		}

		unique_handle& operator=(unique_handle other) noexcept
		{
			this->swap(other);
			return *this;
		}

		unique_handle(unique_handle&& other) noexcept
		{
			this->h = other.h;
			other.h = Policy::get_null();
		}

		unique_handle()
		{
			h = Policy::get_null();
		}

		unique_handle(typename Policy::handle_type handle)
		{
			h = handle;
		}
	};

	void process::kill()
	{
		kill(process::ask);
	}

	process::process(
		boost::filesystem::path executable_file,
		std::function<void(boost::string_ref)> stdout_handler,
		std::function<void(boost::string_ref)> stderr_handler,
		const flags fl) :
		process(executable_file, std::vector<std::string>(), stdout_handler, stderr_handler, fl)
	{

	}
}

#if defined(_WIN32)
#include <windows.h>
static_assert(std::is_same<yet_another_process_library::process::native_handle_type, HANDLE>::value, "invalid assumption about native type");

namespace yet_another_process_library
{
	struct windows_process_handle_policy
	{
		typedef process::native_handle_type handle_type;
		static void close(handle_type handle)
		{
			::CloseHandle(handle);
		}

		static handle_type get_null()
		{
			return INVALID_HANDLE_VALUE;
		}

		static bool is_null(handle_type handle)
		{
			return handle == INVALID_HANDLE_VALUE;
		}
	};

	struct process::impl
	{
		unique_handle<windows_process_handle_policy> process_handle;
	};

	process::process(
		boost::filesystem::path executable_file,
		std::vector<std::wstring> arguments,
		std::function<void(boost::string_ref)> stdout_handler,
		std::function<void(boost::string_ref)> stderr_handler,
		const flags fl)
	{

	}

	process::process(
		boost::filesystem::path executable_file,
		std::vector<std::string> arguments,
		std::function<void(boost::string_ref)> stdout_handler,
		std::function<void(boost::string_ref)> stderr_handler,
		const flags fl)
	{

	}

	void process::write(boost::string_ref input)
	{

	}

	bool process::is_finished()
	{

	}

	boost::optional<int> process::get_exit_status()
	{

	}

	void process::kill(kill_brutality br)
	{

	}

	void process::wait()
	{

	}

	process::native_handle_type process::native_handle()
	{

	}

}
#else
#include <sys/types.h>
#include <sys/wait.h>

namespace yet_another_process_library
{
	struct unix_fd_handle_policy
	{
		typedef process::native_handle_type handle_type;
		static void close(handle_type handle)
		{
			::close(handle);
		}

		static handle_type get_null()
		{
			return -1;
		}

		static bool is_null(handle_type handle)
		{
			return handle == -1;
		}
	};

	struct pipe
	{
		unique_handle<unix_fd_handle_policy> producer;
		unique_handle<unix_fd_handle_policy> consumer;

		void reset()
		{
			producer.reset();
			consumer.reset();
		}
	};

	pipe create_pipe()
	{
		int rawp[2];
		if(::pipe(rawp) == -1)
			throw "FUCK";

		pipe p;
		p.producer = unique_handle<unix_fd_handle_policy>(rawp[0]);
		p.consumer = unique_handle<unix_fd_handle_policy>(rawp[1]);
		return p;
	}

	struct process::impl
	{
		std::mutex stdin_mutex;
		std::thread stdout_reader;
		std::thread stderr_reader;
		unique_handle<unix_fd_handle_policy> process_handle;
		unique_handle<unix_fd_handle_policy> stdin_fd;
		unique_handle<unix_fd_handle_policy> stdout_fd;
		unique_handle<unix_fd_handle_policy> stderr_fd;
		int exit_status = -1;
	};

	process::process(
		boost::filesystem::path executable_file,
		std::vector<std::wstring> arguments,
		std::function<void(boost::string_ref)> stdout_handler,
		std::function<void(boost::string_ref)> stderr_handler,
		const flags fl)
	{

	}

	process::process(
		boost::filesystem::path executable_file,
		std::vector<std::string> arguments,
		std::function<void(boost::string_ref)> stdout_handler,
		std::function<void(boost::string_ref)> stderr_handler,
		const flags fl)
	{
		pipe stdin_pipe;
		pipe stdout_pipe;
		pipe stderr_pipe;

		const bool open_stdin = !is_set(fl, stdin_closed);

		if(open_stdin)
			stdin_pipe = create_pipe();
		if(stdout_handler)
			stdout_pipe = create_pipe();
		if(stderr_handler)
			stderr_pipe = create_pipe();

		native_handle_type pid = fork();
		if(pid < 0)
			throw "FUCK";

		if(pid == 0)
		{
			if(open_stdin)
			{
				dup2(stdin_pipe.producer.get(), 0);
				stdin_pipe.consumer.reset();
			}
			if(stdout_handler)
			{
				dup2(stdout_pipe.consumer.get(), 1);
				stdout_pipe.producer.reset();
			}
			if(stderr_handler)
			{
				dup2(stderr_pipe.consumer.get(), 2);
				stderr_pipe.producer.reset();
			}

			auto close_parent_fds_above = [](int fd)
			{
				const int fd_max=sysconf(_SC_OPEN_MAX);
				for(int i = fd+1; i < fd_max; i++)
					::close(i);
			};
			close_parent_fds_above(2);

			::setpgid(0, 0);

			auto before_exec = [&]()
			{
				const bool should_suspend = is_set(fl, suspended);

				if(should_suspend)
				{
					::kill(0, SIGSTOP);
				}
			};
			before_exec();

			std::string arg0 = executable_file.stem().native();
			std::vector<char*> raw_args;
			raw_args.reserve(arguments.size()+2);
			raw_args.push_back(&arg0[0]);
			std::transform(arguments.begin(), arguments.end(), std::back_inserter(raw_args), [](std::string& s)
			{
				return &s[0];
			});
			raw_args.push_back(nullptr);
			if(is_set(fl, search_path_env))
			{
				::execvp(executable_file.native().c_str(), raw_args.data());
			}
			else
			{
				::execv(executable_file.native().c_str(), raw_args.data());
			}
			_exit(EXIT_FAILURE);
		}

		stdin_pipe.producer.reset();
		stdout_pipe.consumer.reset();
		stderr_pipe.consumer.reset();

		i.reset(new impl());
		i->stdin_fd = std::move(stdin_pipe.consumer);
		i->stdout_fd = std::move(stdout_pipe.producer);
		i->stderr_fd = std::move(stderr_pipe.producer);
		i->process_handle.reset(pid);

		auto reader = [](std::function<void(boost::string_ref)> reader, int fd)
		{
			std::vector<char> buffer(4096);
			ssize_t n;
			while(true)
			{
				n = read(fd, buffer.data(), buffer.size());
				if(n <= 0)
					break;
				reader(boost::string_ref(buffer.data(), static_cast<size_t>(n)));
			}
		};
		if(stdout_handler)
			i->stdout_reader = std::thread(reader, stdout_handler, i->stdout_fd.get());
		if(stderr_handler)
			i->stderr_reader = std::thread(reader, stderr_handler, i->stderr_fd.get());
	}

	void process::close_stdin()
	{
		std::lock_guard<std::mutex> lock(i->stdin_mutex);
		i->stdin_fd.reset();
	}

	bool process::write(boost::string_ref input)
	{
		std::lock_guard<std::mutex> lock(i->stdin_mutex);
		const int res = ::write(i->stdin_fd.get(), input.data(), input.size());
		if(res < 0)
		{
			perror(LINESTR);
			const int err = errno;
			if(err == EBADF)
				throw pipe_closed("stdin is closed");
			return false;
		}
		else if(res == 0)
			return false;
		else
			return true;
	}

	void process::suspend()
	{
		::kill(native_handle(), SIGSTOP);
	}

	void process::resume()
	{
		::kill(native_handle(), SIGCONT);
	}

	bool process::is_finished()
	{
		int exitcode = -1;
		const int res = ::waitpid(native_handle(), &exitcode, WNOHANG);
		if(res > 0)
		{
			i->exit_status = exitcode;
			return true;
		}
		else if(res == 0)
		{
			return false;
		}
		else
		{
			return true;
		}
	}

	boost::optional<int> process::get_exit_status()
	{
		if(is_finished())
		{
			return i->exit_status;
		}
		return boost::none;
	}

	void process::kill(kill_brutality br)
	{
		if(br == force)
			::kill(native_handle(), SIGTERM);
		if(br == ask)
			::kill(native_handle(), SIGKILL);
	}

	void process::wait()
	{
		waitpid(native_handle(), &i->exit_status, 0);
		i->stdin_fd.reset();
		i->stdout_fd.reset();
		i->stderr_fd.reset();
	}

	process::native_handle_type process::native_handle()
	{
		return i->process_handle.get();
	}

	process::~process()
	{
		if(!is_finished())
			std::terminate();
		if(i->stdout_reader.joinable())
			i->stdout_reader.join();
		if(i->stderr_reader.joinable())
			i->stderr_reader.join();
	}

	process::process(process&&) = default;
	process& process::operator=(process&&) = default;
}

#endif<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016 DeepCortex GmbH <legal@eventql.io>
 * Authors:
 *   - Paul Asmuth <paul@eventql.io>
 *   - Laura Schlimmer <laura@eventql.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <iostream>
#include <iomanip>
#include <eventql/cli/benchmarks/local_sql.h>
#include <eventql/util/cli/flagparser.h>
#include <eventql/util/wallclock.h>
#include <eventql/sql/CSTableScanProvider.h>

namespace eventql {
namespace cli {

const String LocalSQLBenchmark::kName_ = "local-sql";
const String LocalSQLBenchmark::kDescription_ = "Benchmark the SQL engine";

LocalSQLBenchmark::LocalSQLBenchmark() :
    verbose_(false),
    num_requests_(-1),
    request_counter_(0) {}

Status LocalSQLBenchmark::execute(
    const std::vector<std::string>& argv,
    FileInputStream* stdin_is,
    OutputStream* stdout_os,
    OutputStream* stderr_os) {
  ::cli::FlagParser flags;

  flags.defineFlag(
      "query",
      ::cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "str",
      "<str>");

  flags.defineFlag(
      "input_cstable",
      ::cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "str",
      "<str>");

  flags.defineFlag(
      "verbose",
      ::cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "flag",
      "<flag>");

  flags.defineFlag(
      "num",
      ::cli::FlagParser::T_INTEGER,
      false,
      "n",
      NULL,
      "total number of request (inifite if unset)",
      "<rate>");

  flags.parseArgv(argv);
  query_ = flags.getString("query");
  if (flags.isSet("verbose")) {
    verbose_ = true;
  }

  auto runtime = csql::Runtime::getDefaultRuntime();
  auto tables = mkRef(new csql::TableRepository());

  for (const auto& t : flags.getStrings("input_cstable")) {
    auto parts = StringUtil::split(t, ":");
    if (parts.size() != 2) {
      return ReturnCode::errorf("EARG", "invalid argument: ", t);
    }

    tables->addProvider(new csql::CSTableScanProvider(parts[0], parts[1]));
  }

  if (flags.isSet("num")) {
    num_requests_ = flags.getInt("num");
  }

  for (size_t i = 0; i < num_requests_; i++) {
    auto rc = runQuery(runtime.get(), tables.get());

    if (!rc.isSuccess()) {
      return rc;
    }
  }

  if (runtimes_us_.size() > 0) {
    std::sort(runtimes_us_.begin(), runtimes_us_.end());
    auto min = runtimes_us_[0];
    auto max = runtimes_us_[runtimes_us_.size() - 1];
    uint32_t total = 0;
    for (auto i : runtimes_us_) {
      total += i;
    }

    auto mean = total / double(runtimes_us_.size());

    uint32_t median;
    if (runtimes_us_.size() % 2 == 0) {
      auto left = runtimes_us_[(runtimes_us_.size() - 1) / 2];
      auto right = runtimes_us_[runtimes_us_.size() / 2];
      median = left + right / 2;
    } else {
      median = runtimes_us_[(runtimes_us_.size() - 1) / 2];
    }

    uint32_t std_dev_sum = 0;
    for (auto i : runtimes_us_) {
      std_dev_sum += pow((i - mean), 2);
    }

    auto std_dev = std_dev_sum / double(runtimes_us_.size());

    std::cout
        << std::endl
        << std::endl
        << std::left
        << std::setw(22)
        << "Query: "
        << query_
        << std::endl
        << std::setw(22)
        << "Complete iterations: "
        << num_requests_
        << std::endl
        << std::setw(22)
        << "Total runtime: "
        << total / 1000000.f << " seconds"
        << std::endl
        << std::endl
        << "Runtimes (ms)"
        << std::endl
        << std::right
        << std::setw(8)
        << "min"
        << std::setw(8)
        << "mean"
        << std::setw(8)
        << "[+/-sd]"
        << std::setw(8)
        << "median"
        << std::setw(8)
        << "max"
        << std::endl
        << std::setprecision(3) << std::fixed
        << std::setw(8)
        << min / 1000.0f
        << std::setw(8)
        << mean / 1000.0f
        << std::setw(8)
        << std_dev / 1000.0f
        << std::setw(8)
        << median / 1000.0f
        << std::setw(8)
        << max / 1000.0f
        << std::endl
        << std::endl
        << "Percentage of the runtimes (ms)"
        << std::endl
        << std::setw(5)
        << "50%"
        << std::setw(5)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.5]
        << std::endl
        << std::setw(5)
        << "66%"
        << std::setw(5)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.66]
        << std::endl
        << std::setw(5)
        << "75%"
        << std::setw(5)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.75]
        << std::endl
        << std::setw(5)
        << "80%"
        << std::setw(5)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.8]
        << std::endl
        << std::setw(5)
        << "90%"
        << std::setw(5)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.9]
        << std::endl
        << std::setw(5)
        << "95%"
        << std::setw(5)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.95]
        << std::endl
        << std::setw(5)
        << "98%"
        << std::setw(5)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.98]
        << std::endl
        << std::setw(5)
        << "99%"
        << std::setw(5)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.99]
        << std::endl
        << std::setw(5)
        << "100%"
        << std::setw(5)
        << runtimes_us_[runtimes_us_.size() - 1]
        << std::endl;
  }

  return Status::success();
}

ReturnCode LocalSQLBenchmark::runQuery(
    csql::Runtime* runtime,
    csql::TableProvider* tables) {
  auto txn = runtime->newTransaction();
  txn->setTableProvider(tables);

  auto t0 = WallClock::unixMicros();

  csql::ResultList result;
  try {
    auto qplan = runtime->buildQueryPlan(txn.get(), query_);
    qplan->execute(0, &result);
  } catch (const std::exception& e) {
    return ReturnCode::error("ERUNTIME", e.what());
  }

  auto t1 = WallClock::unixMicros();
  auto num_rows = result.getNumRows();
  auto runtime_us = t1 - t0;

  if (num_requests_) {
    runtimes_us_.emplace_back(runtime_us);
  }

  if (verbose_) {
    result.debugPrint();

    std::cout
        << "took " << runtime_us / 1000.0f << "ms" << "; "
        << num_rows << " rows returned" << std::endl;

  } else if (
      fmod(++request_counter_, num_requests_ / double(kDefaultNumPrints)) == 0) {
    std::cout
      << request_counter_ << "/"
      << num_requests_ << " requests"
      << std::endl;
  }

  return ReturnCode::success();
}

const String& LocalSQLBenchmark::getName() const {
  return kName_;
}

const String& LocalSQLBenchmark::getDescription() const {
  return kDescription_;
}

void LocalSQLBenchmark::printHelp(OutputStream* stdout_os) const {
  std::cout << StringUtil::format(
      "evqlbench-$0 - $1\n\n",
      kName_,
      kDescription_);

  std::cout <<
      "Usage: evqlbench local-sql [OPTIONS]\n\n"
      "   -q, --query <query>        Specify the SQL query to run\n\n"
      "   -n, --num   <num>           Maximum total number of request (default is infinite)\n";

}

} // namespace cli
} // namespace eventql

<commit_msg>evqlbench local-sql: better unit printing<commit_after>/**
 * Copyright (c) 2016 DeepCortex GmbH <legal@eventql.io>
 * Authors:
 *   - Paul Asmuth <paul@eventql.io>
 *   - Laura Schlimmer <laura@eventql.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <iostream>
#include <iomanip>
#include <eventql/cli/benchmarks/local_sql.h>
#include <eventql/util/cli/flagparser.h>
#include <eventql/util/wallclock.h>
#include <eventql/sql/CSTableScanProvider.h>

namespace eventql {
namespace cli {

const String LocalSQLBenchmark::kName_ = "local-sql";
const String LocalSQLBenchmark::kDescription_ = "Benchmark the SQL engine";

LocalSQLBenchmark::LocalSQLBenchmark() :
    verbose_(false),
    num_requests_(-1),
    request_counter_(0) {}

Status LocalSQLBenchmark::execute(
    const std::vector<std::string>& argv,
    FileInputStream* stdin_is,
    OutputStream* stdout_os,
    OutputStream* stderr_os) {
  ::cli::FlagParser flags;

  flags.defineFlag(
      "query",
      ::cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "str",
      "<str>");

  flags.defineFlag(
      "input_cstable",
      ::cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "str",
      "<str>");

  flags.defineFlag(
      "verbose",
      ::cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "flag",
      "<flag>");

  flags.defineFlag(
      "num",
      ::cli::FlagParser::T_INTEGER,
      false,
      "n",
      NULL,
      "total number of request (inifite if unset)",
      "<rate>");

  flags.parseArgv(argv);
  query_ = flags.getString("query");
  if (flags.isSet("verbose")) {
    verbose_ = true;
  }

  auto runtime = csql::Runtime::getDefaultRuntime();
  auto tables = mkRef(new csql::TableRepository());

  for (const auto& t : flags.getStrings("input_cstable")) {
    auto parts = StringUtil::split(t, ":");
    if (parts.size() != 2) {
      return ReturnCode::errorf("EARG", "invalid argument: ", t);
    }

    tables->addProvider(new csql::CSTableScanProvider(parts[0], parts[1]));
  }

  if (flags.isSet("num")) {
    num_requests_ = flags.getInt("num");
  }

  for (size_t i = 0; i < num_requests_; i++) {
    auto rc = runQuery(runtime.get(), tables.get());

    if (!rc.isSuccess()) {
      return rc;
    }
  }

  if (runtimes_us_.size() > 0) {
    std::sort(runtimes_us_.begin(), runtimes_us_.end());
    auto min = runtimes_us_[0];
    auto max = runtimes_us_[runtimes_us_.size() - 1];
    uint32_t total = 0;
    for (auto i : runtimes_us_) {
      total += i;
    }

    auto mean = total / double(runtimes_us_.size());

    uint32_t median;
    if (runtimes_us_.size() % 2 == 0) {
      auto left = runtimes_us_[(runtimes_us_.size() - 1) / 2];
      auto right = runtimes_us_[runtimes_us_.size() / 2];
      median = left + right / 2;
    } else {
      median = runtimes_us_[(runtimes_us_.size() - 1) / 2];
    }

    uint32_t std_dev_sum = 0;
    for (auto i : runtimes_us_) {
      std_dev_sum += pow((i - mean), 2);
    }

    auto std_dev = std_dev_sum / double(runtimes_us_.size());

    std::cout
        << std::endl
        << std::endl
        << std::left
        << std::setw(22)
        << "Query: "
        << query_
        << std::endl
        << std::setw(22)
        << "Complete iterations: "
        << num_requests_
        << std::endl
        << std::setw(22)
        << "Total runtime: "
        << total / 1000000.f << " s"
        << std::endl
        << std::endl
        << "Runtimes (ms)"
        << std::endl
        << std::right
        << std::setw(8)
        << "min"
        << std::setw(8)
        << "mean"
        << std::setw(8)
        << "[+/-sd]"
        << std::setw(8)
        << "median"
        << std::setw(8)
        << "max"
        << std::endl
        << std::setprecision(3) << std::fixed
        << std::setw(8)
        << min / 1000.0f
        << std::setw(8)
        << mean / 1000.0f
        << std::setw(8)
        << std_dev / 1000.0f
        << std::setw(8)
        << median / 1000.0f
        << std::setw(8)
        << max / 1000.0f
        << std::endl
        << std::endl
        << "Percentage of the runtimes"
        << std::endl
        << std::setw(5)
        << "50%"
        << std::setw(8)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.5] / 1000.f
        << " ms"
        << std::endl
        << std::setw(5)
        << "66%"
        << std::setw(8)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.66] / 1000.f
        << " ms"
        << std::endl
        << std::setw(5)
        << "75%"
        << std::setw(8)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.75] / 1000.f
        << " ms"
        << std::endl
        << std::setw(5)
        << "80%"
        << std::setw(8)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.8] / 1000.f
        << " ms"
        << std::endl
        << std::setw(5)
        << "90%"
        << std::setw(8)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.9] / 1000.f
        << " ms"
        << std::endl
        << std::setw(5)
        << "95%"
        << std::setw(8)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.95] / 1000.f
        << " ms"
        << std::endl
        << std::setw(5)
        << "98%"
        << std::setw(8)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.98] / 1000.f
        << " ms"
        << std::endl
        << std::setw(5)
        << "99%"
        << std::setw(8)
        << runtimes_us_[(runtimes_us_.size() - 1) * 0.99] / 1000.f
        << " ms"
        << std::endl
        << std::setw(5)
        << "100%"
        << std::setw(8)
        << runtimes_us_[runtimes_us_.size() - 1] / 1000.f
        << " ms"
        << std::endl;
  }

  return Status::success();
}

ReturnCode LocalSQLBenchmark::runQuery(
    csql::Runtime* runtime,
    csql::TableProvider* tables) {
  auto txn = runtime->newTransaction();
  txn->setTableProvider(tables);

  auto t0 = WallClock::unixMicros();

  csql::ResultList result;
  try {
    auto qplan = runtime->buildQueryPlan(txn.get(), query_);
    qplan->execute(0, &result);
  } catch (const std::exception& e) {
    return ReturnCode::error("ERUNTIME", e.what());
  }

  auto t1 = WallClock::unixMicros();
  auto num_rows = result.getNumRows();
  auto runtime_us = t1 - t0;

  if (num_requests_) {
    runtimes_us_.emplace_back(runtime_us);
  }

  if (verbose_) {
    result.debugPrint();

    std::cout
        << "took " << runtime_us / 1000.0f << "ms" << "; "
        << num_rows << " rows returned" << std::endl;

  } else if (
      fmod(++request_counter_, num_requests_ / double(kDefaultNumPrints)) == 0) {
    std::cout
      << request_counter_ << "/"
      << num_requests_ << " requests"
      << std::endl;
  }

  return ReturnCode::success();
}

const String& LocalSQLBenchmark::getName() const {
  return kName_;
}

const String& LocalSQLBenchmark::getDescription() const {
  return kDescription_;
}

void LocalSQLBenchmark::printHelp(OutputStream* stdout_os) const {
  std::cout << StringUtil::format(
      "evqlbench-$0 - $1\n\n",
      kName_,
      kDescription_);

  std::cout <<
      "Usage: evqlbench local-sql [OPTIONS]\n\n"
      "   -q, --query <query>        Specify the SQL query to run\n\n"
      "   -n, --num   <num>           Maximum total number of request (default is infinite)\n";

}

} // namespace cli
} // namespace eventql

<|endoftext|>


<commit_before>// Copyright (c) 2017 Franka Emika GmbH
// Use of this source code is governed by the Apache-2.0 license, see LICENSE
#include <franka/gripper.h>

#include <sstream>

#include <franka/exception.h>
#include <research_interface/gripper/types.h>

#include "network.h"

namespace franka {

namespace {

template <typename T, typename... TArgs>
bool executeCommand(Network& network, TArgs&&... args) {
  uint32_t command_id = network.tcpSendRequest<T>(std::forward<TArgs>(args)...);
  typename T::Response response = network.tcpBlockingReceiveResponse<T>(command_id);

  switch (response.status) {
    case T::Status::kSuccess:
      return true;
    case T::Status::kFail:
      throw CommandException("libfranka gripper: Command failed!");
    case T::Status::kUnsuccessful:
      return false;
    default:
      throw ProtocolException("libfranka gripper: Unexpected response while handling command!");
  }
}

GripperState convertGripperState(
    const research_interface::gripper::GripperState& gripper_state) noexcept {
  GripperState converted;
  converted.width = gripper_state.width;
  converted.max_width = gripper_state.max_width;
  converted.is_grasped = gripper_state.is_grasped;
  converted.temperature = gripper_state.temperature;
  converted.time = Duration(gripper_state.message_id);
  return converted;
}

}  // anonymous namespace

Gripper::Gripper(const std::string& franka_address)
    : network_{
          std::make_unique<Network>(franka_address, research_interface::gripper::kCommandPort)} {
  connect<research_interface::gripper::Connect, research_interface::gripper::kVersion>(
      *network_, &ri_version_);
}

Gripper::~Gripper() noexcept = default;
Gripper::Gripper(Gripper&&) noexcept = default;
Gripper& Gripper::operator=(Gripper&&) noexcept = default;

Gripper::ServerVersion Gripper::serverVersion() const noexcept {
  return ri_version_;
}

bool Gripper::homing() const {
  return executeCommand<research_interface::gripper::Homing>(*network_);
}

bool Gripper::grasp(double width,
                    double speed,
                    double force,
                    double epsilon_inner,
                    double epsilon_outer) const {
  research_interface::gripper::Grasp::GraspEpsilon epsilon(epsilon_inner, epsilon_outer);
  return executeCommand<research_interface::gripper::Grasp>(*network_, width, epsilon, speed,
                                                            force);
}

bool Gripper::move(double width, double speed) const {
  return executeCommand<research_interface::gripper::Move>(*network_, width, speed);
}

bool Gripper::stop() const {
  return executeCommand<research_interface::gripper::Stop>(*network_);
}

GripperState Gripper::readOnce() const {
  research_interface::gripper::GripperState gripper_state;
  // Delete old data from the UDP buffer.
  while (network_->udpReceive<decltype(gripper_state)>(&gripper_state)) {
  }

  gripper_state = network_->udpBlockingReceive<decltype(gripper_state)>();
  return convertGripperState(gripper_state);
}

}  // namespace franka
<commit_msg>add aborted case to response status<commit_after>// Copyright (c) 2017 Franka Emika GmbH
// Use of this source code is governed by the Apache-2.0 license, see LICENSE
#include <franka/gripper.h>

#include <sstream>

#include <franka/exception.h>
#include <research_interface/gripper/types.h>

#include "network.h"

namespace franka {

namespace {

template <typename T, typename... TArgs>
bool executeCommand(Network& network, TArgs&&... args) {
  uint32_t command_id = network.tcpSendRequest<T>(std::forward<TArgs>(args)...);
  typename T::Response response = network.tcpBlockingReceiveResponse<T>(command_id);

  switch (response.status) {
    case T::Status::kSuccess:
      return true;
    case T::Status::kFail:
      throw CommandException("libfranka gripper: Command failed!");
    case T::Status::kUnsuccessful:
      return false;
    case T::Status::kAborted:
      throw CommandException("libfranka gripper: Command aborted!");
    default:
      throw ProtocolException("libfranka gripper: Unexpected response while handling command!");
  }
}

GripperState convertGripperState(
    const research_interface::gripper::GripperState& gripper_state) noexcept {
  GripperState converted;
  converted.width = gripper_state.width;
  converted.max_width = gripper_state.max_width;
  converted.is_grasped = gripper_state.is_grasped;
  converted.temperature = gripper_state.temperature;
  converted.time = Duration(gripper_state.message_id);
  return converted;
}

}  // anonymous namespace

Gripper::Gripper(const std::string& franka_address)
    : network_{
          std::make_unique<Network>(franka_address, research_interface::gripper::kCommandPort)} {
  connect<research_interface::gripper::Connect, research_interface::gripper::kVersion>(
      *network_, &ri_version_);
}

Gripper::~Gripper() noexcept = default;
Gripper::Gripper(Gripper&&) noexcept = default;
Gripper& Gripper::operator=(Gripper&&) noexcept = default;

Gripper::ServerVersion Gripper::serverVersion() const noexcept {
  return ri_version_;
}

bool Gripper::homing() const {
  return executeCommand<research_interface::gripper::Homing>(*network_);
}

bool Gripper::grasp(double width,
                    double speed,
                    double force,
                    double epsilon_inner,
                    double epsilon_outer) const {
  research_interface::gripper::Grasp::GraspEpsilon epsilon(epsilon_inner, epsilon_outer);
  return executeCommand<research_interface::gripper::Grasp>(*network_, width, epsilon, speed,
                                                            force);
}

bool Gripper::move(double width, double speed) const {
  return executeCommand<research_interface::gripper::Move>(*network_, width, speed);
}

bool Gripper::stop() const {
  return executeCommand<research_interface::gripper::Stop>(*network_);
}

GripperState Gripper::readOnce() const {
  research_interface::gripper::GripperState gripper_state;
  // Delete old data from the UDP buffer.
  while (network_->udpReceive<decltype(gripper_state)>(&gripper_state)) {
  }

  gripper_state = network_->udpBlockingReceive<decltype(gripper_state)>();
  return convertGripperState(gripper_state);
}

}  // namespace franka
<|endoftext|>


<commit_before>#include <ucontext.h>

namespace factor
{

inline static void *ucontext_stack_pointer(void *uap)
{
	ucontext_t *ucontext = (ucontext_t *)uap;
	return (void *)ucontext->uc_mcontext.gregs[7];
}

inline static unsigned int uap_fpu_status(void *uap)
{
	// XXX mxcsr not available in i386 ucontext
	ucontext_t *ucontext = (ucontext_t *)uap;
	return ucontext->uc_mcontext.fpregs->sw;
}

inline static void uap_clear_fpu_status(void *uap)
{
	ucontext_t *ucontext = (ucontext_t *)uap;
	ucontext->uc_mcontext.fpregs->sw = 0;
}

#define UAP_PROGRAM_COUNTER(ucontext) \
	(((ucontext_t *)(ucontext))->uc_mcontext.gregs[14])

}
<commit_msg>more secret sauce to tease mxcsr out of linux-x86.32 ucontext<commit_after>#include <ucontext.h>

namespace factor
{

// glibc lies about the contents of the fpstate the kernel provides, hiding the FXSR
// environment
struct _fpstate {
	/* Regular FPU environment */
	unsigned long   cw;
	unsigned long   sw;
	unsigned long   tag;
	unsigned long   ipoff;
	unsigned long   cssel;
	unsigned long   dataoff;
	unsigned long   datasel;
	struct _fpreg   _st[8];
	unsigned short  status;
	unsigned short  magic;          /* 0xffff = regular FPU data only */

	/* FXSR FPU environment */
	unsigned long   _fxsr_env[6];   /* FXSR FPU env is ignored */
	unsigned long   mxcsr;
	unsigned long   reserved;
	struct _fpxreg  _fxsr_st[8];    /* FXSR FPU reg data is ignored */
	struct _xmmreg  _xmm[8];
	unsigned long   padding[56];
};

#define X86_FXSR_MAGIC          0x0000

inline static void *ucontext_stack_pointer(void *uap)
{
	ucontext_t *ucontext = (ucontext_t *)uap;
	return (void *)ucontext->uc_mcontext.gregs[7];
}

inline static unsigned int uap_fpu_status(void *uap)
{
	ucontext_t *ucontext = (ucontext_t *)uap;
	struct _fpstate *fpregs = (struct _fpstate *)uap->uc_mcontext.fpregs;
	if (fpregs->magic == X86_FXSR_MAGIC)
	    return fpregs->sw | fpregs->mxcsr;
	else
	    return fpregs->sw;
}

inline static void uap_clear_fpu_status(void *uap)
{
	ucontext_t *ucontext = (ucontext_t *)uap;
	struct _fpstate *fpregs = (struct _fpstate *)uap->uc_mcontext.fpregs;
	fpregs->sw = 0;
	if (fpregs->magic == X86_FXSR_MAGIC)
	    fpregs->mxcsr &= 0xffffffc0;
}

#define UAP_PROGRAM_COUNTER(ucontext) \
	(((ucontext_t *)(ucontext))->uc_mcontext.gregs[14])

}
<|endoftext|>


<commit_before>#include "handler.h"
#include "defs.h"

Handler(Shell sh) {
	this.sh = sh;
}

bool execute(Command c) {
	const char* comm = new const char*;
	const char* args[] = new const char*[];
	comm = c.getCommand();
	args = c.getArgs();

	if (strcmp(c.getCommand(), "cd") == 0) {
		cd(c.getLast());
		return true;
	}
	if (strcmp(c.getCommand(), "pwd") == 0) {
		pwd();
		return true;
	}
	if (strcmp(c.getCommand(), "exit") == 0) {
		exitYoda();
		return true;
	}
	if (strcmp(c.getCommand(), "help") == 0) {
		//help();
		return true;
	}

	if (strcmp(c.getLast(), "&") == 0) {
		//get to the last argument (the '&') to remove it
		for(int i = 0; strcmp(args[i], "\0") != 0; i++)
   		;
  		args[--i] = '\0';

		sh.startAsync(comm, args);
		return true;
	}
	else {
		sh.startSync(comm, args);
		return true;
	}
}

bool cd(const char* path) {
	return sh.setPath(path);
}

void pwd() {
	const char* path = sh.getPath();
	cout<<endl;
	cout<<path<<endl;
}

void exitYoda() {
	exit();
}

void help() {

}
<commit_msg>minor fixes<commit_after>#include "handler.h"
#include "defs.h"

Handler::Handler(Shell *sh) {
	this.sh = sh;
}

bool Handler::execute(Command c) {
	const char* args[] = new const char*[];
	const char* comm = c.getCommand();
	args = c.getArgs();

	if (strcmp(c.getCommand(), "cd") == 0) {
		cd(c.getLast());
		return true;
	}
	if (strcmp(c.getCommand(), "pwd") == 0) {
		pwd();
		return true;
	}
	if (strcmp(c.getCommand(), "exit") == 0) {
		exitYoda();
		return true;
	}
	if (strcmp(c.getCommand(), "help") == 0) {
		//help();
		return true;
	}

	if (strcmp(c.getLast(), "&") == 0) {
		//get to the last argument (the '&') to remove it
		for(int i = 0; strcmp(args[i], "\0") != 0; i++)
   		;
  		args[--i] = '\0';

		sh->startAsync(comm, args);
		return true;
	}
	else {
		sh->startSync(comm, args);
		return true;
	}
}

bool Handler::cd(const char* path) {
	return sh->setPath(path);
}

void Handler::pwd() {
	const char* path = sh->getPath();
	cout<<endl;
	cout<<path<<endl;
}

void Handler::exitYoda() {
	exit();
}

void Handler::help() {

}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2014 Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include <algorithm>
#include <cassert>
#include <cstdarg>
#include <exception>
#include <fstream>
#include <sstream>
#include <string>
#include <amxprof/call_graph_writer_dot.h>
#include <amxprof/statistics_writer_html.h>
#include <amxprof/statistics_writer_json.h>
#include <amxprof/statistics_writer_text.h>
#include "amxpath.h"
#include "fileutils.h"
#include "logprintf.h"
#include "profiler.h"

#define logprintf Use_Printf_isntead_of_logprintf

namespace {
namespace cfg {

ConfigReader server_cfg("server.cfg");

std::string gamemodes =
    server_cfg.GetOptionDefault<std::string>("profiler_gamemodes", "");
std::string filterscripts =
    server_cfg.GetOptionDefault<std::string>("profiler_filterscripts", "");
std::string output_format =
    server_cfg.GetOptionDefault<std::string>("profiler_outputformat", "html");
bool call_graph =
    server_cfg.GetOptionDefault("profiler_callgraph", false);
std::string call_graph_format =
    server_cfg.GetOptionDefault<std::string>("profiler_callgraphformat", "dot");

namespace old {

// old config variables.
bool profile_gamemode =
    server_cfg.GetOptionDefault("profile_gamemode", false);
std::string profile_filterscripts =
    server_cfg.GetOptionDefault<std::string>("profile_filterscripts", "");
std::string profile_format =
    server_cfg.GetOptionDefault<std::string>("profile_format", "html");
bool call_graph =
    server_cfg.GetOptionDefault("call_graph", false);
std::string call_graph_format =
    server_cfg.GetOptionDefault<std::string>("call_graph_format", "dot");

} // namespace old
} // namespace cfg

void Printf(const char *format, ...) {
  std::va_list va;
  va_start(va, format);

  std::string new_format;
  new_format.append("[profiler] ");
  new_format.append(format);

  vlogprintf(new_format.c_str(), va);
  va_end(va);
}

void PrintException(const std::exception &e) {
  Printf("Error: %s", e.what());
}

void SplitString(const std::string &s,
                 char delim,
                 std::vector<std::string> &comps) {
  std::string::size_type begin = 0;
  std::string::size_type end;

  while (begin < s.length()) {
    end = s.find(delim, begin);
    end = (end == std::string::npos) ? s.length() : end;
    comps.push_back(std::string(s.begin() + begin, s.begin() + end));
    begin = end + 1;
  }
}

void ToLower(std::string &s) {
  std::transform(s.begin(), s.end(), s.begin(), ::tolower);
}

std::string ToUnixPath(std::string path) {
  std::replace(path.begin(), path.end(), '\\', '/');
  return path;
}

bool IsCallGraphEnabled() {
  return cfg::call_graph || cfg::old::call_graph;
}

bool IsGameMode(const std::string &amx_path) {
  return amx_path.find("gamemodes/") != std::string::npos;
}

bool IsFilterScript(const std::string &amx_path) {
  return amx_path.find("filterscripts/") != std::string::npos;
}

bool ShouldBeProfiled(const std::string amx_path) {
  if (IsGameMode(amx_path)) {
    if (cfg::old::profile_gamemode) {
      return true;
    }
    std::vector<std::string> gm_names;
    SplitString(cfg::gamemodes, ' ', gm_names);
    for (std::vector<std::string>::const_iterator iterator = gm_names.begin();
         iterator != gm_names.end(); ++iterator) {
      const std::string &gm_name = *iterator;
      if (amx_path == "gamemodes/" + gm_name + ".amx" ||
          amx_path == "gamemodes/" + gm_name) {
        return true;
      }
    }
  }
  if (IsFilterScript(amx_path)) {
    std::vector<std::string> fs_names;
    SplitString(cfg::old::profile_filterscripts, ' ', fs_names);
    SplitString(cfg::filterscripts, ' ', fs_names);
    for (std::vector<std::string>::const_iterator iterator = fs_names.begin();
         iterator != fs_names.end(); ++iterator) {
      const std::string &fs_name = *iterator;
      if (amx_path == "filterscripts/" + fs_name + ".amx" ||
          amx_path == "filterscripts/" + fs_name) {
        return true;
      }
    }
  }
  return false;
}

} // anonymous namespace

Profiler::Profiler(AMX *amx)
 : AMXService<Profiler>(amx),
   prev_debug_(amx->debug),
   prev_callback_(amx->callback),
   profiler_(amx, IsCallGraphEnabled()),
   state_(PROFILER_DISABLED)
{
  AmxPathFinder amx_path_finder;
  amx_path_finder.AddSearchDirectory("gamemodes");
  amx_path_finder.AddSearchDirectory("filterscripts");

  const char *amx_search_path = getenv("AMX_PATH");
  if (amx_search_path != 0) {
    std::vector<std::string> dirs;
    SplitString(amx_search_path, fileutils::kNativePathListSepChar, dirs);
    for (std::vector<std::string>::const_iterator iterator = dirs.begin();
         iterator != dirs.end(); ++iterator) {
      amx_path_finder.AddSearchDirectory(*iterator);
    }
  }

  amx_path_ = ToUnixPath(amx_path_finder.FindAmxPath(amx));
  amx_name_ = fileutils::GetDirectory(amx_path_)
            + "/"
            + fileutils::GetBaseName(amx_path_);

  if (amx_path_.empty()) {
    Printf("Could not find AMX file (try setting AMX_PATH?)");
  }
}

int Profiler::Load() {
  if (ShouldBeProfiled(amx_path_)) {
    Attach();
  }
  return AMX_ERR_NONE;
}

int Profiler::Unload() {
  return AMX_ERR_NONE;
}

int Profiler::Debug() {
  if (state_ == PROFILER_STARTED) {
    try {
      return profiler_.DebugHook(prev_debug_);
    } catch (const std::exception &e) {
      PrintException(e);
    }
  }
  if (prev_debug_ != 0) {
    return prev_debug_(amx());
  }
  return AMX_ERR_NONE;
}

int Profiler::Callback(cell index, cell *result, cell *params) {
  if (state_ == PROFILER_STARTED) {
    try {
      return profiler_.CallbackHook(index, result, params, prev_callback_);
    } catch (const std::exception &e) {
      PrintException(e);
    }
  }
  return prev_callback_(amx(), index, result, params);
}

int Profiler::Exec(cell *retval, int index) {
  if (profiler_.call_stack()->is_empty()) {
    switch (state_) {
      case PROFILER_ATTACHING:
        if (!Attach()) {
          break;
        }
        // fallthrough
      case PROFILER_STARTING:
        state_ = PROFILER_STARTED;
        break;
    }
  }
  if (state_ == PROFILER_STARTED) {
    try {
      int error = profiler_.ExecHook(retval, index, amx_Exec);
      if (state_ == PROFILER_STOPPING
          && profiler_.call_stack()->is_empty()) {
        state_ = PROFILER_STOPPED;
      }
      return error;
    } catch (const std::exception &e) {
      PrintException(e);
    }
  }
  return amx_Exec(amx(), retval, index);
}

ProfilerState Profiler::GetState() const {
  return state_;
}

bool Profiler::Attach() {
  try {
    if (amx_path_.empty()) {
      return false;
    }
    if (state_ >= PROFILER_ATTACHED) {
      return false;
    }

    if (amxprof::HasDebugInfo(amx())) {
      if (debug_info_.Load(amx_path_)) {
        profiler_.set_debug_info(&debug_info_);
      } else {
        Printf("Error loading debug info: %s",
                aux_StrError(debug_info_.last_error()));
      }
    }

    if (debug_info_.is_loaded()) {
      Printf("Attached profiler to %s", amx_path_.c_str());
    } else {
      Printf("Attached profiler to %s (no debug info)", amx_path_.c_str());
    }

    state_ = PROFILER_ATTACHED;
    return true;
  }
  catch (const std::exception &e) {
    PrintException(e);
  }
  return false;
}

bool Profiler::Start() {
  if (state_ < PROFILER_ATTACHED) {
    state_ = PROFILER_ATTACHING;
    return true;
  }
  if (state_ >= PROFILER_ATTACHED) {
    state_ = PROFILER_STARTING;
    return true;
  }
  return false;
}

bool Profiler::Stop() {
  if (state_ >= PROFILER_STARTED) {
    state_ = PROFILER_STOPPING;
    return true;
  }
  return false;
}

bool Profiler::Dump() const {
  try {
    if (state_ < PROFILER_ATTACHED) {
      return false;
    }

    std::string output_format = cfg::output_format;
    if (output_format.empty()) {
      output_format = cfg::old::profile_format;
    }
    ToLower(output_format);
    std::string profile_filename =
        amx_name_ + "-profile." + output_format;
    std::ofstream profile_stream(profile_filename.c_str());

    if (profile_stream.is_open()) {
      amxprof::StatisticsWriter *writer = 0;

      if (output_format == "html") {
        writer = new amxprof::StatisticsWriterHtml;
      } else if (output_format == "txt" ||
                  output_format == "text") {
        writer = new amxprof::StatisticsWriterText;
      } else if (output_format == "json") {
        writer = new amxprof::StatisticsWriterJson;
      } else {
        Printf("Unsupported output format '%s'", output_format.c_str());
      }

      if (writer != 0) {
        Printf("Writing profile to %s", profile_filename.c_str());
        writer->set_stream(&profile_stream);
        writer->set_script_name(amx_path_);
        writer->set_print_date(true);
        writer->set_print_run_time(true);
        writer->Write(profiler_.stats());
        delete writer;
      }

      profile_stream.close();
    } else {
      Printf("Error opening '%s' for writing", profile_filename.c_str());
    }

    if (IsCallGraphEnabled()) {
      std::string call_graph_format = cfg::call_graph_format;
      if (call_graph_format.empty()) {
        call_graph_format = cfg::old::call_graph_format;
      }
      ToLower(call_graph_format);
      std::string call_graph_filename =
          amx_name_ + "-calls." + call_graph_format;
      std::ofstream call_graph_stream(call_graph_filename.c_str());

      if (call_graph_stream.is_open()) {
        amxprof::CallGraphWriterDot *writer = 0;

        if (call_graph_format == "dot") {
          writer = new amxprof::CallGraphWriterDot;
        } else {
          Printf("Unsupported call graph format '%s'",
                  call_graph_format.c_str());
        }

        if (writer != 0) {
          Printf("Writing call graph to %s", call_graph_filename.c_str());
          writer->set_stream(&call_graph_stream);
          writer->set_script_name(amx_path_);
          writer->set_root_node_name("SA-MP Server");
          writer->Write(profiler_.call_graph());
          delete writer;
        }

        call_graph_stream.close();
      } else {
        Printf("Error opening %s for writing", call_graph_filename.c_str());
      }
    }
    return true;
  }
  catch (const std::exception &e) {
    PrintException(e);
  }
  return false;
}
<commit_msg>Fix formatting<commit_after>// Copyright (c) 2011-2014 Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include <algorithm>
#include <cassert>
#include <cstdarg>
#include <exception>
#include <fstream>
#include <sstream>
#include <string>
#include <amxprof/call_graph_writer_dot.h>
#include <amxprof/statistics_writer_html.h>
#include <amxprof/statistics_writer_json.h>
#include <amxprof/statistics_writer_text.h>
#include "amxpath.h"
#include "fileutils.h"
#include "logprintf.h"
#include "profiler.h"

#define logprintf Use_Printf_isntead_of_logprintf

namespace {
namespace cfg {

ConfigReader server_cfg("server.cfg");

std::string gamemodes =
    server_cfg.GetOptionDefault<std::string>("profiler_gamemodes", "");
std::string filterscripts =
    server_cfg.GetOptionDefault<std::string>("profiler_filterscripts", "");
std::string output_format =
    server_cfg.GetOptionDefault<std::string>("profiler_outputformat", "html");
bool call_graph =
    server_cfg.GetOptionDefault("profiler_callgraph", false);
std::string call_graph_format =
    server_cfg.GetOptionDefault<std::string>("profiler_callgraphformat", "dot");

namespace old {

// old config variables.
bool profile_gamemode =
    server_cfg.GetOptionDefault("profile_gamemode", false);
std::string profile_filterscripts =
    server_cfg.GetOptionDefault<std::string>("profile_filterscripts", "");
std::string profile_format =
    server_cfg.GetOptionDefault<std::string>("profile_format", "html");
bool call_graph =
    server_cfg.GetOptionDefault("call_graph", false);
std::string call_graph_format =
    server_cfg.GetOptionDefault<std::string>("call_graph_format", "dot");

} // namespace old
} // namespace cfg

void Printf(const char *format, ...) {
  std::va_list va;
  va_start(va, format);

  std::string new_format;
  new_format.append("[profiler] ");
  new_format.append(format);

  vlogprintf(new_format.c_str(), va);
  va_end(va);
}

void PrintException(const std::exception &e) {
  Printf("Error: %s", e.what());
}

void SplitString(const std::string &s,
                 char delim,
                 std::vector<std::string> &comps) {
  std::string::size_type begin = 0;
  std::string::size_type end;

  while (begin < s.length()) {
    end = s.find(delim, begin);
    end = (end == std::string::npos) ? s.length() : end;
    comps.push_back(std::string(s.begin() + begin, s.begin() + end));
    begin = end + 1;
  }
}

void ToLower(std::string &s) {
  std::transform(s.begin(), s.end(), s.begin(), ::tolower);
}

std::string ToUnixPath(std::string path) {
  std::replace(path.begin(), path.end(), '\\', '/');
  return path;
}

bool IsCallGraphEnabled() {
  return cfg::call_graph || cfg::old::call_graph;
}

bool IsGameMode(const std::string &amx_path) {
  return amx_path.find("gamemodes/") != std::string::npos;
}

bool IsFilterScript(const std::string &amx_path) {
  return amx_path.find("filterscripts/") != std::string::npos;
}

bool ShouldBeProfiled(const std::string amx_path) {
  if (IsGameMode(amx_path)) {
    if (cfg::old::profile_gamemode) {
      return true;
    }
    std::vector<std::string> gm_names;
    SplitString(cfg::gamemodes, ' ', gm_names);
    for (std::vector<std::string>::const_iterator iterator = gm_names.begin();
         iterator != gm_names.end(); ++iterator) {
      const std::string &gm_name = *iterator;
      if (amx_path == "gamemodes/" + gm_name + ".amx" ||
          amx_path == "gamemodes/" + gm_name) {
        return true;
      }
    }
  }
  if (IsFilterScript(amx_path)) {
    std::vector<std::string> fs_names;
    SplitString(cfg::old::profile_filterscripts, ' ', fs_names);
    SplitString(cfg::filterscripts, ' ', fs_names);
    for (std::vector<std::string>::const_iterator iterator = fs_names.begin();
         iterator != fs_names.end(); ++iterator) {
      const std::string &fs_name = *iterator;
      if (amx_path == "filterscripts/" + fs_name + ".amx" ||
          amx_path == "filterscripts/" + fs_name) {
        return true;
      }
    }
  }
  return false;
}

} // anonymous namespace

Profiler::Profiler(AMX *amx)
 : AMXService<Profiler>(amx),
   prev_debug_(amx->debug),
   prev_callback_(amx->callback),
   profiler_(amx, IsCallGraphEnabled()),
   state_(PROFILER_DISABLED)
{
  AmxPathFinder amx_path_finder;
  amx_path_finder.AddSearchDirectory("gamemodes");
  amx_path_finder.AddSearchDirectory("filterscripts");

  const char *amx_search_path = getenv("AMX_PATH");
  if (amx_search_path != 0) {
    std::vector<std::string> dirs;
    SplitString(amx_search_path, fileutils::kNativePathListSepChar, dirs);
    for (std::vector<std::string>::const_iterator iterator = dirs.begin();
         iterator != dirs.end(); ++iterator) {
      amx_path_finder.AddSearchDirectory(*iterator);
    }
  }

  amx_path_ = ToUnixPath(amx_path_finder.FindAmxPath(amx));
  amx_name_ = fileutils::GetDirectory(amx_path_)
            + "/"
            + fileutils::GetBaseName(amx_path_);

  if (amx_path_.empty()) {
    Printf("Could not find AMX file (try setting AMX_PATH?)");
  }
}

int Profiler::Load() {
  if (ShouldBeProfiled(amx_path_)) {
    Attach();
  }
  return AMX_ERR_NONE;
}

int Profiler::Unload() {
  return AMX_ERR_NONE;
}

int Profiler::Debug() {
  if (state_ == PROFILER_STARTED) {
    try {
      return profiler_.DebugHook(prev_debug_);
    } catch (const std::exception &e) {
      PrintException(e);
    }
  }
  if (prev_debug_ != 0) {
    return prev_debug_(amx());
  }
  return AMX_ERR_NONE;
}

int Profiler::Callback(cell index, cell *result, cell *params) {
  if (state_ == PROFILER_STARTED) {
    try {
      return profiler_.CallbackHook(index, result, params, prev_callback_);
    } catch (const std::exception &e) {
      PrintException(e);
    }
  }
  return prev_callback_(amx(), index, result, params);
}

int Profiler::Exec(cell *retval, int index) {
  if (profiler_.call_stack()->is_empty()) {
    switch (state_) {
      case PROFILER_ATTACHING:
        if (!Attach()) {
          break;
        }
        // fallthrough
      case PROFILER_STARTING:
        state_ = PROFILER_STARTED;
        break;
    }
  }
  if (state_ == PROFILER_STARTED) {
    try {
      int error = profiler_.ExecHook(retval, index, amx_Exec);
      if (state_ == PROFILER_STOPPING
          && profiler_.call_stack()->is_empty()) {
        state_ = PROFILER_STOPPED;
      }
      return error;
    } catch (const std::exception &e) {
      PrintException(e);
    }
  }
  return amx_Exec(amx(), retval, index);
}

ProfilerState Profiler::GetState() const {
  return state_;
}

bool Profiler::Attach() {
  try {
    if (amx_path_.empty()) {
      return false;
    }
    if (state_ >= PROFILER_ATTACHED) {
      return false;
    }

    if (amxprof::HasDebugInfo(amx())) {
      if (debug_info_.Load(amx_path_)) {
        profiler_.set_debug_info(&debug_info_);
      } else {
        Printf("Error loading debug info: %s",
                aux_StrError(debug_info_.last_error()));
      }
    }

    if (debug_info_.is_loaded()) {
      Printf("Attached profiler to %s", amx_path_.c_str());
    } else {
      Printf("Attached profiler to %s (no debug info)", amx_path_.c_str());
    }

    state_ = PROFILER_ATTACHED;
    return true;
  }
  catch (const std::exception &e) {
    PrintException(e);
  }
  return false;
}

bool Profiler::Start() {
  if (state_ < PROFILER_ATTACHED) {
    state_ = PROFILER_ATTACHING;
    return true;
  }
  if (state_ >= PROFILER_ATTACHED) {
    state_ = PROFILER_STARTING;
    return true;
  }
  return false;
}

bool Profiler::Stop() {
  if (state_ >= PROFILER_STARTED) {
    state_ = PROFILER_STOPPING;
    return true;
  }
  return false;
}

bool Profiler::Dump() const {
  try {
    if (state_ < PROFILER_ATTACHED) {
      return false;
    }

    std::string output_format = cfg::output_format;
    if (output_format.empty()) {
      output_format = cfg::old::profile_format;
    }
    ToLower(output_format);
    std::string profile_filename =
        amx_name_ + "-profile." + output_format;
    std::ofstream profile_stream(profile_filename.c_str());

    if (profile_stream.is_open()) {
      amxprof::StatisticsWriter *writer = 0;

      if (output_format == "html") {
        writer = new amxprof::StatisticsWriterHtml;
      } else if (output_format == "txt" || output_format == "text") {
        writer = new amxprof::StatisticsWriterText;
      } else if (output_format == "json") {
        writer = new amxprof::StatisticsWriterJson;
      } else {
        Printf("Unsupported output format '%s'", output_format.c_str());
      }

      if (writer != 0) {
        Printf("Writing profile to %s", profile_filename.c_str());
        writer->set_stream(&profile_stream);
        writer->set_script_name(amx_path_);
        writer->set_print_date(true);
        writer->set_print_run_time(true);
        writer->Write(profiler_.stats());
        delete writer;
      }

      profile_stream.close();
    } else {
      Printf("Error opening '%s' for writing", profile_filename.c_str());
    }

    if (IsCallGraphEnabled()) {
      std::string call_graph_format = cfg::call_graph_format;
      if (call_graph_format.empty()) {
        call_graph_format = cfg::old::call_graph_format;
      }
      ToLower(call_graph_format);
      std::string call_graph_filename =
          amx_name_ + "-calls." + call_graph_format;
      std::ofstream call_graph_stream(call_graph_filename.c_str());

      if (call_graph_stream.is_open()) {
        amxprof::CallGraphWriterDot *writer = 0;

        if (call_graph_format == "dot") {
          writer = new amxprof::CallGraphWriterDot;
        } else {
          Printf("Unsupported call graph format '%s'",
                  call_graph_format.c_str());
        }

        if (writer != 0) {
          Printf("Writing call graph to %s", call_graph_filename.c_str());
          writer->set_stream(&call_graph_stream);
          writer->set_script_name(amx_path_);
          writer->set_root_node_name("SA-MP Server");
          writer->Write(profiler_.call_graph());
          delete writer;
        }

        call_graph_stream.close();
      } else {
        Printf("Error opening %s for writing", call_graph_filename.c_str());
      }
    }
    return true;
  }
  catch (const std::exception &e) {
    PrintException(e);
  }
  return false;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: module.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: th $ $Date: 2001-05-10 10:49:42 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _VOS_MODULE_HXX_
#define _VOS_MODULE_HXX_

#ifndef _VOS_OBJECT_HXX_
#   include <vos/object.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#   include <rtl/ustring.hxx>
#endif
#ifndef _OSL_MODULE_H_
#   include <osl/module.h>
#endif

#ifdef _USE_NAMESPACE
namespace vos
{
#endif

class OModule : public OObject
{
    VOS_DECLARE_CLASSINFO(VOS_NAMESPACE(OModule, vos));

public:

    /// default c'tor
    OModule();

    /// this c'tor is a combination of the default c'tor and load()
    OModule(const ::rtl::OUString& strModuleName, sal_Int32 nRtldMode = SAL_LOADMODULE_DEFAULT);
    virtual ~OModule();

    /// loads the specified module
    sal_Bool SAL_CALL load(const ::rtl::OUString& strModuleName, sal_Int32 nRtldMode = SAL_LOADMODULE_DEFAULT);

    /// unloads the currently loaded module
    void SAL_CALL unload();

    /// returns sal_True, if a module is loaded, sal_False otherwise
    sal_Bool SAL_CALL isLoaded();

#if 0
    // not implemented yet
    // returns the name of the currently loaded module or an empty string if none.
    ::rtl::OUString SAL_CALL getModuleName();
#endif

    /// returns a pointer to the specified Symbol if found, NULL otherwise
    void* SAL_CALL getSymbol(const ::rtl::OUString& strSymbolName);

protected:

    oslModule m_Module;
};

#ifdef _USE_NAMESPACE
}
#endif

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.4.138); FILE MERGED 2005/09/05 17:40:11 rt 1.4.138.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: module.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 09:00:02 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _VOS_MODULE_HXX_
#define _VOS_MODULE_HXX_

#ifndef _VOS_OBJECT_HXX_
#   include <vos/object.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#   include <rtl/ustring.hxx>
#endif
#ifndef _OSL_MODULE_H_
#   include <osl/module.h>
#endif

#ifdef _USE_NAMESPACE
namespace vos
{
#endif

class OModule : public OObject
{
    VOS_DECLARE_CLASSINFO(VOS_NAMESPACE(OModule, vos));

public:

    /// default c'tor
    OModule();

    /// this c'tor is a combination of the default c'tor and load()
    OModule(const ::rtl::OUString& strModuleName, sal_Int32 nRtldMode = SAL_LOADMODULE_DEFAULT);
    virtual ~OModule();

    /// loads the specified module
    sal_Bool SAL_CALL load(const ::rtl::OUString& strModuleName, sal_Int32 nRtldMode = SAL_LOADMODULE_DEFAULT);

    /// unloads the currently loaded module
    void SAL_CALL unload();

    /// returns sal_True, if a module is loaded, sal_False otherwise
    sal_Bool SAL_CALL isLoaded();

#if 0
    // not implemented yet
    // returns the name of the currently loaded module or an empty string if none.
    ::rtl::OUString SAL_CALL getModuleName();
#endif

    /// returns a pointer to the specified Symbol if found, NULL otherwise
    void* SAL_CALL getSymbol(const ::rtl::OUString& strSymbolName);

protected:

    oslModule m_Module;
};

#ifdef _USE_NAMESPACE
}
#endif

#endif

<|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <cstring>
#include <string>
#include <vector>
#include <iomanip>
#include <cmath>
#include <list>
#include <bitset>

using namespace std;

#define ll long long
#define lson l,mid,id<<1
#define rson mid+1,r,id<<1|1

typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
typedef pair<double, double>pdd;

const double eps = 1e-6;
const ll  LINF = 0x3f3f3f3f3f3f3f3fLL;
const int INF = 0x3f3f3f3f;
const double FINF = 1e18;

#define x first
#define y second

#define REP(i,j,k) for(int i =(j);i<=(k);i++)
#define REPD(i,j,k) for(int i =(j);i>=(k);i--)
#define print(x) cout<<(x)<<endl;
#define IOS ios::sync_with_stdio(0);cin.tie(0);

char a[300005],b[100005];

void Init(){
	cin>>b;

	return ;
}

void Solve(){
	int lena;
	lena =strlen(a);

	REP(i,0,lena-1){
		a[lena+i]=a[i];
	}
	a[lena*2]=0;

	cout<<((search(a,a+2*lena,b,b+strlen(b))-a)<2*lena)<<endl;

	return ;
}

int main(){
#ifdef LOCAL
	freopen("hdu2203.in","r",stdin);
#endif

	while(cin>>a)
	Init(),Solve();
	return 0;
}<commit_msg>update hdu2203<commit_after>#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <cstring>
#include <string>
#include <vector>
#include <iomanip>
#include <cmath>
#include <list>
#include <bitset>

using namespace std;

#define ll long long
#define lson l,mid,id<<1
#define rson mid+1,r,id<<1|1

typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
typedef pair<double, double>pdd;

const double eps = 1e-6;
const ll  LINF = 0x3f3f3f3f3f3f3f3fLL;
const int INF = 0x3f3f3f3f;
const double FINF = 1e18;

#define x first
#define y second

#define REP(i,j,k) for(int i =(j);i<=(k);i++)
#define REPD(i,j,k) for(int i =(j);i>=(k);i--)
#define print(x) cout<<(x)<<endl;
#define IOS ios::sync_with_stdio(0);cin.tie(0);

char a[300005],b[100005];

void Init(){
	cin>>b;

	return ;
}

void Solve(){
	int lena;
	lena =strlen(a);

	REP(i,0,lena-1){
		a[lena+i]=a[i];
	}
	a[lena*2]=0;

	cout<<(((search(a,a+2*lena,b,b+strlen(b))-a)<2*lena)?"yes":"no")<<endl;

	return ;
}

int main(){
#ifdef LOCAL
	freopen("hdu2203.in","r",stdin);
#endif

	while(cin>>a)
	Init(),Solve();
	return 0;
}<|endoftext|>


<commit_before>#include "gamelib/editor/tools/VertexTool.hpp"
#include <SFML/Graphics.hpp>
#include "imgui.h"
#include "imgui-SFML.h"
#include "gamelib/core/ecs/Entity.hpp"
#include "gamelib/editor/tools/SelectTool.hpp"
#include "gamelib/editor/tools/ToolUtils.hpp"
#include "gamelib/editor/EditorShared.hpp"
#include "gamelib/components/editor/BrushComponent.hpp"
#include "gamelib/components/geometry/Polygon.hpp"

namespace gamelib
{
    VertexTool::VertexTool() :
        _selected(-1),
        _snappoint(true)
    { }

    void VertexTool::onMousePressed()
    {
        auto brush = getIfBrush(EditorShared::getSelectTool().getSelected());
        if (brush)
            selectDragBoxes(brush->getBrushPolygon()->getPolygon(), &_selected);

        if (_selected == (size_t)-1)
            EditorShared::getSelectTool().onMousePressed();
    }

    void VertexTool::onDrag()
    {
        auto brush = getIfBrush(EditorShared::getSelectTool().getSelected());

        if (brush && _selected != (size_t)-1)
        {
            if (_snappoint)
                brush->edit(_selected, snap(brush->getBrushPolygon()->getPolygon(), EditorShared::getMouse(), _selected));
            else
                brush->edit(_selected, EditorShared::getMouseSnapped());
        }
    }

    void VertexTool::drawGui()
    {
        ImGui::Checkbox("Snap to points", &_snappoint);
    }

    void VertexTool::render(sf::RenderTarget& target)
    {
        auto brush = getIfBrush(EditorShared::getSelectTool().getSelected());
        if (brush)
            drawDragBoxes(target, brush->getBrushPolygon()->getPolygon(), _selected);
    }
}
<commit_msg>Fix SelectTool switching modes when clicking with VertexTool<commit_after>#include "gamelib/editor/tools/VertexTool.hpp"
#include <SFML/Graphics.hpp>
#include "imgui.h"
#include "imgui-SFML.h"
#include "gamelib/core/ecs/Entity.hpp"
#include "gamelib/editor/tools/SelectTool.hpp"
#include "gamelib/editor/tools/ToolUtils.hpp"
#include "gamelib/editor/EditorShared.hpp"
#include "gamelib/components/editor/BrushComponent.hpp"
#include "gamelib/components/geometry/Polygon.hpp"

namespace gamelib
{
    VertexTool::VertexTool() :
        _selected(-1),
        _snappoint(true)
    { }

    void VertexTool::onMousePressed()
    {
        auto brush = getIfBrush(EditorShared::getSelectTool().getSelected());
        if (brush)
            selectDragBoxes(brush->getBrushPolygon()->getPolygon(), &_selected);

        if (_selected == (size_t)-1)
            EditorShared::getSelectTool().select(EditorShared::getMouse().x, EditorShared::getMouse().y);
    }

    void VertexTool::onDrag()
    {
        auto brush = getIfBrush(EditorShared::getSelectTool().getSelected());

        if (brush && _selected != (size_t)-1)
        {
            if (_snappoint)
                brush->edit(_selected, snap(brush->getBrushPolygon()->getPolygon(), EditorShared::getMouse(), _selected));
            else
                brush->edit(_selected, EditorShared::getMouseSnapped());
        }
    }

    void VertexTool::drawGui()
    {
        ImGui::Checkbox("Snap to points", &_snappoint);
    }

    void VertexTool::render(sf::RenderTarget& target)
    {
        auto brush = getIfBrush(EditorShared::getSelectTool().getSelected());
        if (brush)
            drawDragBoxes(target, brush->getBrushPolygon()->getPolygon(), _selected);
    }
}
<|endoftext|>


<commit_before>#pragma once

#include <distributions/io/protobuf.hpp>
#include <distributions/models_fwd.hpp>
#include <loom/common.hpp>
#include <loom/protobuf_stream.hpp>
#include <loom/models.hpp>
#include <loom/schema.pb.h>

namespace loom
{

inline std::ostream & operator<< (
        std::ostream & os,
        const ::google::protobuf::Message & message)
{
    return os << message.ShortDebugString();
}

namespace protobuf
{

using namespace ::protobuf::loom;
using namespace ::protobuf::distributions;
using namespace ::distributions::protobuf;

template<class Value>
struct Fields;

template<>
struct Fields<bool>
{
    static auto get (ProductModel_SparseValue & value)
        -> decltype(* value.mutable_booleans())
    {
        return * value.mutable_booleans();
    }

    static const auto get (const ProductModel_SparseValue & value)
        -> decltype(value.booleans())
    {
        return value.booleans();
    }
};

template<>
struct Fields<uint32_t>
{
    static auto get (ProductModel_SparseValue & value)
        -> decltype(* value.mutable_counts())
    {
        return * value.mutable_counts();
    }

    static const auto get (const ProductModel_SparseValue & value)
        -> decltype(value.counts())
    {
        return value.counts();
    }
};

template<>
struct Fields<float>
{
    static auto get (ProductModel_SparseValue & value)
        -> decltype(* value.mutable_reals())
    {
        return * value.mutable_reals();
    }

    static const auto get (const ProductModel_SparseValue & value)
        -> decltype(value.reals())
    {
        return value.reals();
    }
};

struct SparseValueSchema
{
    size_t booleans_size;
    size_t counts_size;
    size_t reals_size;

    SparseValueSchema () :
        booleans_size(0),
        counts_size(0),
        reals_size(0)
    {
    }

    size_t total_size () const
    {
        return booleans_size + counts_size + reals_size;
    }

    static size_t total_size (const ProductModel_SparseValue & value)
    {
        return value.booleans_size()
            + value.counts_size()
            + value.reals_size();
    }

    static size_t observed_count (const ProductModel_SparseValue & value)
    {
        size_t count = 0;
        for (size_t i = 0, size = value.observed_size(); i < size; ++i) {
            if (value.observed(i)) {
                count += 1;
            }
        }
        return count;
    }

    void clear ()
    {
        booleans_size = 0;
        counts_size = 0;
        reals_size = 0;
    }

    void operator+= (const SparseValueSchema & other)
    {
        booleans_size += other.booleans_size;
        counts_size += other.counts_size;
        reals_size += other.reals_size;
    }

    void validate (const ProductModel_SparseValue & value) const
    {
        LOOM_ASSERT_EQ(value.observed_size(), total_size());
        LOOM_ASSERT_LE(value.booleans_size(), booleans_size);
        LOOM_ASSERT_LE(value.counts_size(), counts_size);
        LOOM_ASSERT_LE(value.reals_size(), reals_size);
        LOOM_ASSERT_EQ(observed_count(value), total_size(value));
    }

    bool is_valid (const ProductModel_SparseValue & value) const
    {
        return value.observed_size() == total_size()
            and value.booleans_size() <= booleans_size
            and value.counts_size() <= counts_size
            and value.reals_size() <= reals_size
            and observed_count(value) == total_size(value);
    }

    template<class Fun>
    void for_each_datatype (Fun & fun) const
    {
        fun(static_cast<bool *>(nullptr), booleans_size);
        fun(static_cast<uint32_t *>(nullptr), counts_size);
        fun(static_cast<float *>(nullptr), reals_size);
    }

    bool operator== (const SparseValueSchema & other) const
    {
        return booleans_size == other.booleans_size
            and counts_size == other.counts_size
            and reals_size == other.reals_size;
    }

    friend std::ostream & operator<< (
        std::ostream & os,
        const SparseValueSchema & schema)
    {
        return os << "{" <<
            schema.booleans_size << ", " <<
            schema.counts_size << ", " <<
            schema.reals_size << "}";
    }
};

// This accounts for the many-to-one C++-to-protobuf model mapping,
// e.g. DirichletDiscrete<N> maps to DirichletDiscrete for all N.
struct ModelCounts
{
    size_t bb;
    size_t dd;
    size_t dpd;
    size_t gp;
    size_t nich;

    ModelCounts () :
        bb(0),
        dd(0),
        dpd(0),
        gp(0),
        nich(0)
    {}

    size_t & operator[] (BetaBernoulli *) { return bb; }
    template<int max_dim>
    size_t & operator[] (DirichletDiscrete<max_dim> *) { return dd; }
    size_t & operator[] (DirichletProcessDiscrete *) { return dpd; }
    size_t & operator[] (GammaPoisson *) { return gp; }
    size_t & operator[] (NormalInverseChiSq *) { return nich; }
};

template<class Model>
struct Shareds;

template<>
struct Shareds<BetaBernoulli>
{
    static auto get (ProductModel_Shared & value)
        -> decltype(* value.mutable_bb())
    {
        return * value.mutable_bb();
    }

    static const auto get (const ProductModel_Shared & value)
        -> decltype(value.bb())
    {
        return value.bb();
    }
};

template<int max_dim>
struct Shareds<DirichletDiscrete<max_dim>>
{
    static auto get (ProductModel_Shared & value)
        -> decltype(* value.mutable_dd())
    {
        return * value.mutable_dd();
    }

    static const auto get (const ProductModel_Shared & value)
        -> decltype(value.dd())
    {
        return value.dd();
    }
};

template<>
struct Shareds<DirichletProcessDiscrete>
{
    static auto get (ProductModel_Shared & value)
        -> decltype(* value.mutable_dpd())
    {
        return * value.mutable_dpd();
    }

    static const auto get (const ProductModel_Shared & value)
        -> decltype(value.dpd())
    {
        return value.dpd();
    }
};

template<>
struct Shareds<GammaPoisson>
{
    static auto get (ProductModel_Shared & value)
        -> decltype(* value.mutable_gp())
    {
        return * value.mutable_gp();
    }

    static const auto get (const ProductModel_Shared & value)
        -> decltype(value.gp())
    {
        return value.gp();
    }
};

template<>
struct Shareds<NormalInverseChiSq>
{
    static auto get (ProductModel_Shared & value)
        -> decltype(* value.mutable_nich())
    {
        return * value.mutable_nich();
    }

    static const auto get (const ProductModel_Shared & value)
        -> decltype(value.nich())
    {
        return value.nich();
    }
};

template<class Model>
struct Groups;

template<>
struct Groups<BetaBernoulli>
{
    static auto get (ProductModel_Group & value)
        -> decltype(* value.mutable_bb())
    {
        return * value.mutable_bb();
    }

    static const auto get (const ProductModel_Group & value)
        -> decltype(value.bb())
    {
        return value.bb();
    }
};

template<int max_dim>
struct Groups<DirichletDiscrete<max_dim>>
{
    static auto get (ProductModel_Group & value)
        -> decltype(* value.mutable_dd())
    {
        return * value.mutable_dd();
    }

    static const auto get (const ProductModel_Group & value)
        -> decltype(value.dd())
    {
        return value.dd();
    }
};

template<>
struct Groups<DirichletProcessDiscrete>
{
    static auto get (ProductModel_Group & value)
        -> decltype(* value.mutable_dpd())
    {
        return * value.mutable_dpd();
    }

    static const auto get (const ProductModel_Group & value)
        -> decltype(value.dpd())
    {
        return value.dpd();
    }
};

template<>
struct Groups<GammaPoisson>
{
    static auto get (ProductModel_Group & value)
        -> decltype(* value.mutable_gp())
    {
        return * value.mutable_gp();
    }

    static const auto get (const ProductModel_Group & value)
        -> decltype(value.gp())
    {
        return value.gp();
    }
};

template<>
struct Groups<NormalInverseChiSq>
{
    static auto get (ProductModel_Group & value)
        -> decltype(* value.mutable_nich())
    {
        return * value.mutable_nich();
    }

    static const auto get (const ProductModel_Group & value)
        -> decltype(value.nich())
    {
        return value.nich();
    }
};

template<class Model>
struct GridPriors;

template<>
struct GridPriors<BetaBernoulli>
{
    static const auto get (const ProductModel_HyperPrior & value)
        -> decltype(value.bb())
    {
        return value.bb();
    }
};

template<int max_dim>
struct GridPriors<DirichletDiscrete<max_dim>>
{
    static const auto get (const ProductModel_HyperPrior & value)
        -> decltype(value.dd())
    {
        return value.dd();
    }
};

template<>
struct GridPriors<DirichletProcessDiscrete>
{
    static const auto get (const ProductModel_HyperPrior & value)
        -> decltype(value.dpd())
    {
        return value.dpd();
    }
};

template<>
struct GridPriors<GammaPoisson>
{
    static const auto get (const ProductModel_HyperPrior & value)
        -> decltype(value.gp())
    {
        return value.gp();
    }
};

template<>
struct GridPriors<NormalInverseChiSq>
{
    static const auto get (const ProductModel_HyperPrior & value)
        -> decltype(value.nich())
    {
        return value.nich();
    }
};

} // namespace protobuf
} // namespace loom
<commit_msg>Simplify protobuf.hpp with macros<commit_after>#pragma once

#include <distributions/io/protobuf.hpp>
#include <distributions/models_fwd.hpp>
#include <loom/common.hpp>
#include <loom/protobuf_stream.hpp>
#include <loom/models.hpp>
#include <loom/schema.pb.h>

namespace loom
{

inline std::ostream & operator<< (
        std::ostream & os,
        const ::google::protobuf::Message & message)
{
    return os << message.ShortDebugString();
}

namespace protobuf
{

using namespace ::protobuf::loom;
using namespace ::protobuf::distributions;
using namespace ::distributions::protobuf;

//----------------------------------------------------------------------------
// Datatypes

template<class Value> struct Fields;

#define DECLARE_DATATYPE(Typename, fieldname)                       \
template<>                                                          \
struct Fields<Typename>                                             \
{                                                                   \
    static auto get (ProductModel_SparseValue & value)              \
        -> decltype(* value.mutable_ ## fieldname())                \
    {                                                               \
        return * value.mutable_ ## fieldname();                     \
    }                                                               \
    static const auto get (const ProductModel_SparseValue & value)  \
        -> decltype(value.fieldname())                              \
    {                                                               \
        return value.fieldname();                                   \
    }                                                               \
};

DECLARE_DATATYPE(bool, booleans)
DECLARE_DATATYPE(uint32_t, counts)
DECLARE_DATATYPE(float, reals)

#undef DECLARE_DATATYPE

struct SparseValueSchema
{
    size_t booleans_size;
    size_t counts_size;
    size_t reals_size;

    SparseValueSchema () :
        booleans_size(0),
        counts_size(0),
        reals_size(0)
    {
    }

    size_t total_size () const
    {
        return booleans_size + counts_size + reals_size;
    }

    static size_t total_size (const ProductModel_SparseValue & value)
    {
        return value.booleans_size()
            + value.counts_size()
            + value.reals_size();
    }

    static size_t observed_count (const ProductModel_SparseValue & value)
    {
        size_t count = 0;
        for (size_t i = 0, size = value.observed_size(); i < size; ++i) {
            if (value.observed(i)) {
                count += 1;
            }
        }
        return count;
    }

    void clear ()
    {
        booleans_size = 0;
        counts_size = 0;
        reals_size = 0;
    }

    void operator+= (const SparseValueSchema & other)
    {
        booleans_size += other.booleans_size;
        counts_size += other.counts_size;
        reals_size += other.reals_size;
    }

    void validate (const ProductModel_SparseValue & value) const
    {
        LOOM_ASSERT_EQ(value.observed_size(), total_size());
        LOOM_ASSERT_LE(value.booleans_size(), booleans_size);
        LOOM_ASSERT_LE(value.counts_size(), counts_size);
        LOOM_ASSERT_LE(value.reals_size(), reals_size);
        LOOM_ASSERT_EQ(observed_count(value), total_size(value));
    }

    bool is_valid (const ProductModel_SparseValue & value) const
    {
        return value.observed_size() == total_size()
            and value.booleans_size() <= booleans_size
            and value.counts_size() <= counts_size
            and value.reals_size() <= reals_size
            and observed_count(value) == total_size(value);
    }

    template<class Fun>
    void for_each_datatype (Fun & fun) const
    {
        fun(static_cast<bool *>(nullptr), booleans_size);
        fun(static_cast<uint32_t *>(nullptr), counts_size);
        fun(static_cast<float *>(nullptr), reals_size);
    }

    bool operator== (const SparseValueSchema & other) const
    {
        return booleans_size == other.booleans_size
            and counts_size == other.counts_size
            and reals_size == other.reals_size;
    }

    friend std::ostream & operator<< (
        std::ostream & os,
        const SparseValueSchema & schema)
    {
        return os << "{" <<
            schema.booleans_size << ", " <<
            schema.counts_size << ", " <<
            schema.reals_size << "}";
    }
};

//----------------------------------------------------------------------------
// Models

// This accounts for the many-to-one C++-to-protobuf model mapping,
// e.g. DirichletDiscrete<N> maps to DirichletDiscrete for all N.
struct ModelCounts
{
    size_t bb;
    size_t dd;
    size_t dpd;
    size_t gp;
    size_t nich;

    ModelCounts () :
        bb(0),
        dd(0),
        dpd(0),
        gp(0),
        nich(0)
    {}

    size_t & operator[] (BetaBernoulli *) { return bb; }
    template<int max_dim>
    size_t & operator[] (DirichletDiscrete<max_dim> *) { return dd; }
    size_t & operator[] (DirichletProcessDiscrete *) { return dpd; }
    size_t & operator[] (GammaPoisson *) { return gp; }
    size_t & operator[] (NormalInverseChiSq *) { return nich; }
};

template<class Model> struct Shareds;
template<class Model> struct Groups;
template<class Model> struct GridPriors;

#define DECLARE_MODEL(template_, Typename, fieldname)               \
template_                                                           \
struct Shareds<Typename>                                            \
{                                                                   \
    static auto get (ProductModel_Shared & value)                   \
        -> decltype(* value.mutable_ ## fieldname())                \
    {                                                               \
        return * value.mutable_ ## fieldname();                     \
    }                                                               \
    static const auto get (const ProductModel_Shared & value)       \
        -> decltype(value.fieldname())                              \
    {                                                               \
        return value.fieldname();                                   \
    }                                                               \
};                                                                  \
template_                                                           \
struct Groups<Typename>                                             \
{                                                                   \
    static auto get (ProductModel_Group & value)                    \
        -> decltype(* value.mutable_ ## fieldname())                \
    {                                                               \
        return * value.mutable_ ## fieldname();                     \
    }                                                               \
    static const auto get (const ProductModel_Group & value)        \
        -> decltype(value.fieldname())                              \
    {                                                               \
        return value.fieldname();                                   \
    }                                                               \
};                                                                  \
template_                                                           \
struct GridPriors<Typename>                                         \
{                                                                   \
    static const auto get (const ProductModel_HyperPrior & value)   \
        -> decltype(value.fieldname())                              \
    {                                                               \
        return value.fieldname();                                   \
    }                                                               \
};

DECLARE_MODEL(template<>, BetaBernoulli, bb)
DECLARE_MODEL(template<int max_dim>, DirichletDiscrete<max_dim>, dd)
DECLARE_MODEL(template<>, DirichletProcessDiscrete, dpd)
DECLARE_MODEL(template<>, GammaPoisson, gp)
DECLARE_MODEL(template<>, NormalInverseChiSq, nich)

#undef DECLARE_MODEL

} // namespace protobuf
} // namespace loom
<|endoftext|>