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