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...)); };
}
}