<commit_before>/*
* Vool - gnuplot interface using popen to pipe data to gnuplot
*
* Copyright (c) 2016 <NAME> - www.lukas-bergdoll.net
*
* This code is licensed under the Apache License 2.0 (https://opensource.org/licenses/Apache-2.0)
*/

#ifndef VOOL_GNP_H_INCLUDED
#define VOOL_GNP_H_INCLUDED

#include <vector>
#include <string>
#include <fstream>
#include <iostream>

namespace vool
{

template<typename T> struct plot_data_2D;

class gnuplot
{
public:
	using filepath_t = const char*;

	explicit gnuplot(filepath_t);

	gnuplot(const gnuplot&) = delete;
	gnuplot(gnuplot&&);

	gnuplot& operator=(const gnuplot&) = delete;
	gnuplot& operator=(gnuplot&&);

	~gnuplot() noexcept;

	template<typename... Ts> void operator() (const Ts&...);

	void operator<< (std::string);

	void name_axis(
		const std::string& = "x-axis",
		const std::string& = "y-axis",
		const std::string& = "z-axis"
	);

	void set_terminal_png(const uint32_t, const uint32_t);

	void set_terminal_window(const uint32_t, const uint32_t);

	void set_png_filename(filepath_t);

	void add_linestyle(
		const uint32_t,
		const std::string&,
		const uint32_t = 2,
		const uint32_t = 1,
		const uint32_t = 2,
		const float = 1.5f
	);

	void add_grid();

	template<typename T> void write_and_plot(
		const std::vector<plot_data_2D<T>>&,
		filepath_t
	);

	template<typename T> void write(
		const std::vector<plot_data_2D<T>>&,
		filepath_t
	);

	template<typename T> void plot(
		const std::vector<plot_data_2D<T>>&,
		filepath_t
	);

private:
	FILE* _gnuplot_pipe;
};

template<typename T> struct plot_data_2D
{
public:
	using point_t = std::pair<T, T>; // first = x second = y

	explicit plot_data_2D(
		const std::vector<point_t>,
		const uint32_t,
		const std::string&
	);

	const auto& points() const { return _points; }
	const auto linestyle() const { return _linestyle; }
	const auto index() const { return _index; }
	const auto& name() const { return _name; }

private:
	std::vector<point_t> _points;
	uint32_t _linestyle;
	uint32_t _index;
	std::string _name;
};

// ----- IMPLEMENTATION -----

namespace gnuplot_util
{
	// automatic string conversion from variadic pack
	inline void cat(const std::string& arg, std::string& ret) { ret += arg; }
	inline void cat(const char* arg, std::string& ret) { ret += arg; }

	// overload if T is not an string or const char*
	template<typename T> void cat(const T& arg, std::string& ret)
	{
		ret += std::to_string(arg);
	}

	template<typename... Ts> std::string concatenate(Ts&&... args)
	{
		std::string command;
		auto wFunc = [&command](auto&& arg)
		{
			cat(std::forward<decltype(arg)>(arg), command);
		};

		static_cast<void>(std::initializer_list<int>
		{
			0, (wFunc(std::forward<Ts>(args)), 0)...
		});
		return command;
	}
}

// --- plot_data_2D ---

template<typename T> plot_data_2D<T>::plot_data_2D(
	const std::vector<point_t> points,
	const uint32_t index,
	const std::string& name
)
	: _points(points), _linestyle(index + 1), _index(index), _name(name)
{ }

// --- gnuplot ---

template<typename... Ts> void gnuplot::operator() (const Ts&... args)
{
	auto command = gnuplot_util::concatenate(args...);
	command += "\n";

	fprintf(_gnuplot_pipe, "%s\n", command.c_str());
	fflush(_gnuplot_pipe);
}

template<typename T> void gnuplot::write_and_plot(
	const std::vector<plot_data_2D<T>>& plots,
	filepath_t filepath
)
{
	write(plots, filepath);
	plot(plots, filepath);
}

template<typename T> void gnuplot::write(
	const std::vector<plot_data_2D<T>>& plots,
	filepath_t filepath
)
{
	if (plots.size() == 0)
		return;
<commit_msg>Use perfect forwarding in gnuplot::operator()<commit_after>/*
* Vool - gnuplot interface using popen to pipe data to gnuplot
*
* Copyright (c) 2016 <NAME> - www.lukas-bergdoll.net
*
* This code is licensed under the Apache License 2.0 (https://opensource.org/licenses/Apache-2.0)
*/

#ifndef VOOL_GNP_H_INCLUDED
#define VOOL_GNP_H_INCLUDED

#include <vector>
#include <string>
#include <fstream>
#include <iostream>

namespace vool
{

template<typename T> struct plot_data_2D;

class gnuplot
{
public:
	using filepath_t = const char*;

	explicit gnuplot(filepath_t);

	gnuplot(const gnuplot&) = delete;
	gnuplot(gnuplot&&);

	gnuplot& operator=(const gnuplot&) = delete;
	gnuplot& operator=(gnuplot&&);

	~gnuplot() noexcept;

	template<typename... Ts> void operator() (Ts&&...);

	void operator<< (std::string);

	void name_axis(
		const std::string& = "x-axis",
		const std::string& = "y-axis",
		const std::string& = "z-axis"
	);

	void set_terminal_png(const uint32_t, const uint32_t);

	void set_terminal_window(const uint32_t, const uint32_t);

	void set_png_filename(filepath_t);

	void add_linestyle(
		const uint32_t,
		const std::string&,
		const uint32_t = 2,
		const uint32_t = 1,
		const uint32_t = 2,
		const float = 1.5f
	);

	void add_grid();

	template<typename T> void write_and_plot(
		const std::vector<plot_data_2D<T>>&,
		filepath_t
	);

	template<typename T> void write(
		const std::vector<plot_data_2D<T>>&,
		filepath_t
	);

	template<typename T> void plot(
		const std::vector<plot_data_2D<T>>&,
		filepath_t
	);

private:
	FILE* _gnuplot_pipe;
};

template<typename T> struct plot_data_2D
{
public:
	using point_t = std::pair<T, T>; // first = x second = y

	explicit plot_data_2D(
		const std::vector<point_t>,
		const uint32_t,
		const std::string&
	);

	const auto& points() const { return _points; }
	const auto linestyle() const { return _linestyle; }
	const auto index() const { return _index; }
	const auto& name() const { return _name; }

private:
	std::vector<point_t> _points;
	uint32_t _linestyle;
	uint32_t _index;
	std::string _name;
};

// ----- IMPLEMENTATION -----

namespace gnuplot_util
{
	// automatic string conversion from variadic pack
	inline void cat(const std::string& arg, std::string& ret) { ret += arg; }
	inline void cat(const char* arg, std::string& ret) { ret += arg; }

	// overload if T is not an string or const char*
	template<typename T> void cat(const T& arg, std::string& ret)
	{
		ret += std::to_string(arg);
	}

	template<typename... Ts> std::string concatenate(Ts&&... args)
	{
		std::string command;
		auto wFunc = [&command](auto&& arg)
		{
			cat(std::forward<decltype(arg)>(arg), command);
		};

		static_cast<void>(std::initializer_list<int>
		{
			0, (wFunc(std::forward<Ts>(args)), 0)...
		});
		return command;
	}
}

// --- plot_data_2D ---

template<typename T> plot_data_2D<T>::plot_data_2D(
	const std::vector<point_t> points,
	const uint32_t index,
	const std::string& name
)
	: _points(points), _linestyle(index + 1), _index(index), _name(name)
{ }

// --- gnuplot ---

template<typename... Ts> void gnuplot::operator() (Ts&&... args)
{
	auto command = gnuplot_util::concatenate(std::forward<Ts>(args)...);
	command += "\n";

	fprintf(_gnuplot_pipe, "%s\n", command.c_str());
	fflush(_gnuplot_pipe);
}

template<typename T> void gnuplot::write_and_plot(
	const std::vector<plot_data_2D<T>>& plots,
	filepath_t filepath
)
{
	write(plots, filepath);
	plot(plots, filepath);
}

template<typename T> void gnuplot::write(
	const std::vector<plot_data_2D<T>>& plots,
	filepath_t filepath
)
{
	if (plots.size() == 0)
		return;

{'fraction_non_alphanumeric': 0.15326633165829145, 'fraction_numerical': 0.014517029592406477, 'mean_word_length': 4.524286815728605, 'pattern_counts': {'":': 0, '<': 80, '<?xml version=': 0, '>': 76, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4841135', 'n_tokens_mistral': 2881, 'n_tokens_neox': 2693, 'n_words': 646}