C++ Utility

Convert

Convert.h

#pragma once

#include <string>
#include <charconv>

#define __Convert_ToStringFunc__(x) #x
#define __Convert_ToString__(x) __Convert_ToStringFunc__(x)
#define __Convert_Line__ __Convert_ToString__(__LINE__)

template<typename...Args>
std::string __Convert_Combine__(Args&&... args)
{
	std::string res;
	(res.append(args), ...);
	return res;
}

#define __Convert_ThrowEx__(...) throw std::runtime_error(__Convert_Combine__(__FILE__ ": " __Convert_Line__ ": ", __func__, ": ", __VA_ARGS__))

template<typename T, typename Args>
[[nodiscard]] T __From_String_Impl__(const std::string& value, const Args args)
{
	T res;
	auto [p, e] = std::from_chars(value.c_str(), value.c_str() + value.length(), res, args);
	if (e != std::errc{}) __Convert_ThrowEx__("convert error: invalid literal: ", p);
	return res;
}

template<typename T, typename...Args>
[[nodiscard]] std::string __To_String_Impl__(const T& value, Args&& ... args)
{
	char res[65] = { 0 };
	auto [p, e] = std::to_chars(res, res + 65, value, std::forward<Args>(args)...);
	if (e != std::errc{}) __Convert_ThrowEx__("convert error: invalid literal: ", p);
	return res;
}

namespace Convert
{
	template<typename T,std::enable_if_t<std::negation_v<typename std::disjunction<
			typename std::is_integral<T>::value,
			typename std::is_floating_point<T>::value
		>::value>, int> = 0>
	[[nodiscard]] std::string ToString(const T& value)
	{
		return std::string(value);
	}
	
	template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
	[[nodiscard]] std::string ToString(const T value, const int base = 10)
	{
		return __To_String_Impl__<T>(value, base);
	}
	
	template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
	[[nodiscard]] std::string ToString(const T value)
	{
		return __To_String_Impl__<T>(value);
	}

#ifdef _MSC_VER
	template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
	[[nodiscard]] std::string ToString(const T value, const std::chars_format& fmt)
	{
		return __To_String_Impl__<T>(value, fmt);
	}
	
	template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
	[[nodiscard]] std::string ToString(const T value, const std::chars_format& fmt, const int precision)
	{
		return __To_String_Impl__<T>(value, fmt, precision);
	}
#endif
	
	template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
	[[nodiscard]] T FromString(const std::string& value, const int base = 10)
	{
		return __From_String_Impl__<T>(value, base);
	}

#ifdef _MSC_VER
	template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
	[[nodiscard]] T FromString(const std::string& value, const std::chars_format& fmt = std::chars_format::general)
	{
		return __From_String_Impl__<T>(value, fmt);
	}
#endif
}

#undef __Convert_ToStringFunc__
#undef __Convert_ToString__
#undef __Convert_Line__
#undef __Convert_ThrowEx__

Arguments

Arguments.h

#pragma once

#include <cstdint>
#include <string>
#include <any>
#include <functional>
#include <optional>
#include <sstream>
#include <variant>

template <typename ...Args>
std::string __Arguments_Combine__(Args&&... args)
{
	std::ostringstream ss;
	(ss << ... << args);
	return ss.str();
}

#define __Arguments_ToStringFunc__(x) #x
#define __Arguments_ToString__(x) __Arguments_ToStringFunc__(x)

#define __Arguments_Line__ __Arguments_ToString__(__LINE__)

#define __Arguments_ThrowEx__(...) throw std::runtime_error(__Arguments_Combine__( __FILE__ ": " __Arguments_Line__ ":\n", __VA_ARGS__))

namespace ArgumentsParse
{
	using ArgLengthType = std::uint8_t;

	template<ArgLengthType Len>
	struct SetValueTypeImp
	{
		using Type = std::vector<std::string_view>;
	};
	
	template<>
	struct SetValueTypeImp<1>
	{
		using Type = std::string_view;
	};
	
	template<>
	struct SetValueTypeImp<0>
	{
		using Type = std::nullopt_t;
	};
	
	class IArgument
	{
	public:
		using SetValueType = std::variant<SetValueTypeImp<0>::Type, SetValueTypeImp<1>::Type, SetValueTypeImp<2>::Type>;

		IArgument() = default;
		virtual ~IArgument() = default;
		IArgument(const IArgument& iArgument) = default;
		IArgument(IArgument&& iArgument) = default;
		IArgument& operator=(const IArgument& iArgument) = default;
		IArgument& operator=(IArgument&& iArgument) = default;
		
		virtual void Set(const SetValueType& value) = 0;
		virtual operator std::string() const = 0;
		virtual std::any Get() const = 0;
		virtual std::string GetName() const = 0;
		virtual std::string GetDesc() const = 0;
		virtual ArgLengthType GetArgLength() const = 0;
	};
	
	template <typename T = std::string, ArgLengthType ArgLength = 1>
	class Argument final : public IArgument
	{
	public:
		using ValueType = T;
		using ValueTypeOpt = std::optional<ValueType>;

		struct ConvertResult
		{
			ValueTypeOpt Value;
			std::string Message;
		};

		using ConvertFuncParamTypeImp = typename SetValueTypeImp<ArgLength>::Type;
		using ConvertFuncParamType = const ConvertFuncParamTypeImp&;
		using ConvertFuncType = std::function<ConvertResult(ConvertFuncParamType)>;

		explicit Argument(
			std::string name,
			std::string desc,
			ValueTypeOpt defaultValue,
			ConvertFuncType convert = DefaultConvert):
			name(std::move(name)),
			desc(std::move(desc)),
			val(std::move(defaultValue)),
			convert(convert) {}

		explicit Argument(
			std::string name,
			std::string desc,
			ConvertFuncType convert = DefaultConvert) :
			name(std::move(name)),
			desc(std::move(desc)),
			convert(convert) {}

		void Set(const SetValueType& value) override
		{
			ConvertFuncParamTypeImp valueUnbox = std::get<decltype(valueUnbox)>(value);
			auto [v, e] = convert(valueUnbox);
			if (v.has_value())
			{
				val = v;
			}
			else
			{
				__Arguments_ThrowEx__(name, ": ", e.c_str());
			}
		}

		[[nodiscard]] std::any Get() const override { return val; }

		[[nodiscard]] std::string GetName() const override { return name; }

		[[nodiscard]] std::string GetDesc() const override { return desc; }

		[[nodiscard]] operator std::string() const override { return name; }

		ArgLengthType GetArgLength() const override { return ArgLength; }

		static ConvertResult DefaultConvert(ConvertFuncParamType value) { return { ValueTypeOpt(value), {} }; }

	private:
		std::string name;
		std::string desc;
		std::any val = std::nullopt;
		ConvertFuncType convert;
	};

	class Arguments
	{
	public:
		void Parse(int argc, char** argv);

		template <typename T, ArgLengthType ArgLength>
		void Add(Argument<T, ArgLength>& arg)
		{
			if (args.find(arg.GetName()) != args.end())
			{
				__Arguments_ThrowEx__(args.at(arg)->GetName(), ": exists");
			}
			args[arg.GetName()] = &arg;
		}

		std::string GetDesc();

		template <typename T = std::string>
		T Value(const std::string& arg) const
		{
			try
			{
				return Get<T>(arg).value();
			}
			catch (const std::exception& e)
			{
				const auto name = args.at(arg)->GetName();
				__Arguments_ThrowEx__(name.empty() ? "(Default)" : name, ": ", e.what());
			}
		}

		template <typename T = std::string>
		std::optional<T> Get(const std::string& arg) const
		{
			return std::any_cast<std::optional<T>>(args.at(arg)->Get());
		}

		IArgument* operator[](const std::string& arg);

	private:
		std::unordered_map<std::string, IArgument*> args;
	};
	
#define ArgumentOptionHpp(option, ...)\
	enum class option { __VA_ARGS__ };\
	static auto __##option##_map__ = (([i = 0](std::string str) mutable\
	{\
		str.erase(std::remove(str.begin(), str.end(), ' '), str.end());\
		std::unordered_map<option, const std::string> res{};\
		std::string item;\
		std::stringstream stringStream(str);\
		while (std::getline(stringStream, item, ',')) res.emplace(static_cast<option>(i++), item);\
		return res;\
	})(#__VA_ARGS__));\
	std::string ToString(const option& in);\
	std::optional<option> To##option(const std::string& in);\
	std::string option##Desc(const std::string& defaultValue = "");

#define ArgumentOptionCpp(option, ...)\
	std::string ToString(const option& in) { return __##option##_map__.at(in); }\
	std::optional<option> To##option(const std::string& in) { for (const auto& [k, v] : __##option##_map__) if (v == in) return k; return std::nullopt; }\
	std::string option##Desc(const std::string& defaultValue)\
	{\
		std::ostringstream oss{};\
		oss << "[";\
		for (const auto kv : __##option##_map__)\
		{\
			const auto sm = kv.second;\
			if (sm == defaultValue)\
			{\
				oss << "(" << sm << ")|";\
				continue;\
			}\
			oss << sm << "|";\
		}\
		auto res = oss.str();\
		res[res.length() - 1] = ']';\
		return res;\
	}

#define ArgumentOption(option, ...)\
	ArgumentOptionHpp(option, __VA_ARGS__)\
	ArgumentOptionCpp(option, __VA_ARGS__)
}

#undef __Arguments_ToStringFunc__
#undef __Arguments_ToString__
#undef __Arguments_Line__
#undef __Arguments_ThrowEx__

Arguments.cpp

#include "Arguments.h"

#include <algorithm>
#include <queue>

#define __Arguments_ToStringFunc__(x) #x
#define __Arguments_ToString__(x) __Arguments_ToStringFunc__(x)
#define __Arguments_Line__ __Arguments_ToString__(__LINE__)
#define __Arguments_ThrowEx__(...) throw std::runtime_error(__Arguments_Combine__( __FILE__ ": " __Arguments_Line__ ":\n", __VA_ARGS__))

namespace ArgumentsParse
{
	std::string Arguments::GetDesc()
	{
		std::priority_queue<std::string, std::vector<std::string>, std::greater<>> item{};
		std::vector<std::string::size_type> lens{};
		std::transform(
			args.begin(),
			args.end(),
			std::back_inserter(lens),
			[&](const std::pair<std::string, IArgument*>& x) { item.push(x.first); return x.first.length(); });
		const auto maxLen = *std::max_element(lens.begin(), lens.end()) + 1;
		std::ostringstream ss;
		while (!item.empty())
		{
			const auto i = item.top();
			ss << __Arguments_Combine__(
				i, std::string(maxLen - i.length(), ' '),
				args.at(i)->GetDesc(), "\n");
			item.pop();
		}
		return ss.str();
	}

	void Arguments::Parse(const int argc, char** argv)
	{
		if (argc < 2)
		{
			__Arguments_ThrowEx__(argv[0], " [options]");
		}
#define UnrecognizedOption(...) __Arguments_ThrowEx__("Unrecognized option: ", __VA_ARGS__)
#define MissingArgument(...) __Arguments_ThrowEx__("Missing argument for option: ", __VA_ARGS__)
		for (auto i = 1; i < argc; ++i)
		{
			auto pos = args.find(argv[i]);
			ArgLengthType def = 0;
			if (pos == args.end())
			{
				pos = args.find("");
				def = 1;
			}
			if (pos != args.end())
			{
				const auto len = pos->second->GetArgLength();
				if (len + i - def < argc)
				{
					auto setValue = [&]() -> IArgument::SetValueType {
						switch (len)
						{
						case 0:
							return { std::nullopt };
						case 1:
							return { argv[i + 1 - def] };
						default:
							std::vector<std::string_view> values{};
							for (auto j = 0; j < len; ++j)
							{
								values.emplace_back(argv[i + j + 1 - def]);
							}
							return { values };
						}
					}();
					pos->second->Set(setValue);
					i += len - def;
				}
				else
				{
					MissingArgument(argv[i]);
				}
			}
			else
			{
				UnrecognizedOption(argv[i]);
			}
		}
	}

	IArgument* Arguments::operator[](const std::string& arg)
	{
		return args.at(arg);
	}
}

Macro

Macro.h

#pragma once

#pragma region private

#define __Macro_ToStringFunc__(x) #x

#pragma endregion private

#pragma region public

#define MacroToString(x) __Macro_ToStringFunc__(x)
#define MacroLine MacroToString(__LINE__)

#if (defined _WIN32 || _WIN64)
	#define MacroWindows
#endif

#ifdef _MSC_VER
	#define MacroFunctionName __FUNCSIG__
#elif defined __GNUC__
	#define MacroFunctionName __PRETTY_FUNCTION__
#else
	#define MacroFunctionName __func__
#endif

#pragma endregion public

Bit

Bit.h

#pragma once

#include <cstdint>
#include <type_traits>
#include <climits>

template<typename T, std::size_t... N>
constexpr T __EndianSwapImpl__(T i, std::index_sequence<N...>)
{
	return (((i >> N * CHAR_BIT & static_cast<std::uint8_t>(-1)) << (sizeof(T) - 1 - N) * CHAR_BIT) | ...);
}

namespace Bit
{
	enum class Endian
	{
#ifdef _WIN32
		Little = 0,
		Big = 1,
		Native = Little
#else
		Little = __ORDER_LITTLE_ENDIAN__,
		Big = __ORDER_BIG_ENDIAN__,
		Native = __BYTE_ORDER__
#endif
	};
	
	template<typename T, typename U = std::make_unsigned_t<T>>
	constexpr U EndianSwap(T i)
	{
		return __EndianSwapImpl__<U>(i, std::make_index_sequence<sizeof(T)>{});
	}
}

CSV

CSV.h

#pragma once

#include <fstream>
#include <memory>

class CsvFile
{
	std::ofstream fs;
	const std::uint64_t bufferSize = 1024 * 1024;
	std::unique_ptr<char[]> buffer = std::make_unique<char[]>(bufferSize);
	bool isFirst;
	const std::string separator;
	const std::string escapeSeq;
	const std::string specialChars;
public:
	explicit CsvFile(const std::string& filename, std::string separator = ";");

	CsvFile() = delete;

	~CsvFile();

	void Flush();

	void EndRow();

	CsvFile& operator << (CsvFile& (*val)(CsvFile&));

	CsvFile& operator << (const char* val);

	CsvFile& operator << (const std::string& val);

	template<typename T>
	CsvFile& operator << (const T& val)
	{
		return Write(val);
	}

	static CsvFile& EndRow(CsvFile& file);

	static CsvFile& Flush(CsvFile& file);

private:
	template<typename T>
	CsvFile& Write(const T& val)
	{
		if (!isFirst)
		{
			fs << separator;
		}
		else
		{
			isFirst = false;
		}
		fs << val;
		return *this;
	}

	[[nodiscard]] std::string Escape(const std::string& val) const;
};

CSV.cpp

#include "CSV.h"

#include <sstream>
#include <utility>

CsvFile::CsvFile(const std::string& filename, std::string separator)
	: isFirst(true),
	separator(std::move(separator)),
	escapeSeq("\""),
	specialChars("\"")
{
	fs.exceptions(std::ios::failbit | std::ios::badbit);
	fs.open(filename);
	fs.rdbuf()->pubsetbuf(buffer.get(), bufferSize);
}

CsvFile::~CsvFile()
{
	Flush();
	fs.close();
}

void CsvFile::Flush()
{
	fs.flush();
}

void CsvFile::EndRow()
{
	fs << "\n";
	isFirst = true;
}

CsvFile& CsvFile::operator<<(CsvFile&(* val)(CsvFile&))
{
	return val(*this);
}

CsvFile& CsvFile::operator<<(const char* val)
{
	return Write(Escape(val));
}

CsvFile& CsvFile::operator<<(const std::string& val)
{
	return Write(Escape(val));
}

CsvFile& CsvFile::EndRow(CsvFile& file)
{
	file.EndRow();
	return file;
}

CsvFile& CsvFile::Flush(CsvFile& file)
{
	file.Flush();
	return file;
}

std::string CsvFile::Escape(const std::string& val) const
{
	std::ostringstream result;
	result << '"';
	std::string::size_type to, from = 0u, len = val.length();
	while (from < len &&
		std::string::npos != (to = val.find_first_of(specialChars, from)))
	{
		result << val.substr(from, to - from) << escapeSeq << val[to];
		from = to + 1;
	}
	result << val.substr(from) << '"';
	return result.str();
}

String

String.h

#pragma once

#include <cctype>
#include <algorithm>
#include <string>

namespace String
{
	template<typename T>
	void ToUpper(T& string)
	{
		std::transform(string.begin(), string.end(), string.begin(), static_cast<int(*)(int)>(std::toupper));
	}

	template<typename T>
	void ToLower(T& string)
	{
		std::transform(string.begin(), string.end(), string.begin(), static_cast<int(*)(int)>(std::tolower));
	}

	template<typename...Args>
	void StringCombine(std::string& str, Args&&... args)
	{
		(str.append(args), ...);
	}
}

Thread

Thread.h

#pragma once

#include <condition_variable>
#include <mutex>
#include <list>

namespace Thread
{
    template<typename T>
    class Channel
    {
    public:
        void Write(const T& data)
        {
            std::unique_lock<std::mutex> lock(mtx);
            buffer.push_back(data);
            lock.unlock();
            cv.notify_all();
        }

        T Read()
        {
            std::unique_lock<std::mutex> lock(mtx);
            cv.wait(lock, [&]() { return !buffer.empty(); });
            const auto item = buffer.front();
            buffer.pop_front();
            return item;
        }

        [[nodiscard]] auto Length() const
        {
            return buffer.size();
        }
    	
    private:
        std::list<T> buffer{};
        std::mutex mtx{};
        std::condition_variable cv{};
    };
}

Time

Time.h

#pragma once

#include <ctime>

namespace Time
{
	void Gmt(tm* gmt, time_t const* time);

	void Local(tm* local, time_t const* time);
}

Time.cpp

#include "Time.h"

namespace Time
{
	void Gmt(tm* const gmt, time_t const* const time)
	{
#if (defined _WIN32 || _WIN64)
		gmtime_s(gmt, time);
#else
		gmtime_r(time, gmt);
#endif
	}

	void Local(tm* const local, time_t const* const time)
	{
#if (defined _WIN32 || _WIN64)
		localtime_s(local, time);
#else
		localtime_r(time, local);
#endif
	}
}

Function

Function.h

#pragma once

namespace Function
{
    template <typename G, typename F>
    decltype(auto) Compose(G&& g, F&& f)
	{
        return [=](auto&& ...x) { return f(g(x...)); };
    }
}

 

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注