Massively overengineered logger to support different character types.
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <locale>
|
||||
@@ -17,6 +19,7 @@
|
||||
|
||||
#include "./iterators.hpp"
|
||||
#include "../internal/common.hpp"
|
||||
#include "../util/traits.hpp"
|
||||
|
||||
namespace mijin
|
||||
{
|
||||
@@ -33,8 +36,56 @@ namespace mijin
|
||||
// public traits
|
||||
//
|
||||
|
||||
template<typename TString>
|
||||
using char_type_t = decltype(std::string_view(std::declval<TString>()))::value_type;
|
||||
template<typename T>
|
||||
inline constexpr bool is_string_v = is_template_instance_v<std::basic_string, std::remove_cvref_t<T>>;
|
||||
|
||||
template<typename T>
|
||||
concept std_string_type = is_string_v<T>;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_string_view_v = is_template_instance_v<std::basic_string_view, std::remove_cvref_t<T>>;
|
||||
|
||||
template<typename T>
|
||||
concept std_string_view_type = is_string_view_v<T>;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_char_v = is_any_type_v<std::remove_cvref_t<T>, char, wchar_t, char8_t, char16_t, char32_t>;
|
||||
|
||||
template<typename T>
|
||||
concept char_type = is_char_v<T>;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_cstring_v = std::is_pointer_v<T> && is_char_v<std::remove_pointer_t<T>>;
|
||||
|
||||
template<typename T>
|
||||
concept cstring_type = is_cstring_v<T>;
|
||||
|
||||
template<typename T>
|
||||
struct str_char_type
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template<char_type T>
|
||||
struct str_char_type<T*>
|
||||
{
|
||||
using type = std::remove_cvref_t<T>;
|
||||
};
|
||||
|
||||
template<std_string_view_type T>
|
||||
struct str_char_type<T>
|
||||
{
|
||||
using type = typename std::remove_cvref_t<T>::value_type;
|
||||
};
|
||||
|
||||
template<std_string_type T>
|
||||
struct str_char_type<T>
|
||||
{
|
||||
using type = typename std::remove_cvref_t<T>::value_type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using str_char_type_t = str_char_type<T>::type;
|
||||
|
||||
//
|
||||
// public types
|
||||
@@ -255,7 +306,7 @@ template<typename TString>
|
||||
[[nodiscard]]
|
||||
auto trimPrefix(TString&& string)
|
||||
{
|
||||
return trimPrefix(string, detail::DEFAULT_TRIM_CHARS<char_type_t<TString>>);
|
||||
return trimPrefix(string, detail::DEFAULT_TRIM_CHARS<str_char_type_t<TString>>);
|
||||
}
|
||||
|
||||
template<typename TString, typename TChars>
|
||||
@@ -269,7 +320,7 @@ template<typename TString>
|
||||
[[nodiscard]]
|
||||
auto trimSuffix(TString&& string)
|
||||
{
|
||||
return trimSuffix(string, detail::DEFAULT_TRIM_CHARS<char_type_t<TString>>);
|
||||
return trimSuffix(string, detail::DEFAULT_TRIM_CHARS<str_char_type_t<TString>>);
|
||||
}
|
||||
|
||||
template<typename TString, typename TChars>
|
||||
@@ -283,7 +334,7 @@ template<typename TString>
|
||||
[[nodiscard]]
|
||||
auto trim(TString&& string)
|
||||
{
|
||||
return trim(string, detail::DEFAULT_TRIM_CHARS<char_type_t<TString>>);
|
||||
return trim(string, detail::DEFAULT_TRIM_CHARS<str_char_type_t<TString>>);
|
||||
}
|
||||
|
||||
template<typename TLeft, typename TRight>
|
||||
@@ -425,7 +476,7 @@ struct Join
|
||||
{
|
||||
const char* delimiter;
|
||||
|
||||
explicit Join(const char* delimiter_) MIJIN_NOEXCEPT : delimiter(delimiter_) {}
|
||||
explicit Join(const char* delimiter_) MIJIN_NOEXCEPT: delimiter(delimiter_) {}
|
||||
};
|
||||
|
||||
template<typename TIterable>
|
||||
@@ -433,6 +484,142 @@ auto operator|(TIterable&& iterable, const Join& joiner)
|
||||
{
|
||||
return join(std::forward<TIterable>(iterable), joiner.delimiter);
|
||||
}
|
||||
} // namespace pipe
|
||||
|
||||
struct [[nodiscard]] ConvertCharTypeResult
|
||||
{
|
||||
unsigned numRead = 0;
|
||||
unsigned numWritten = 0;
|
||||
|
||||
constexpr operator bool() const MIJIN_NOEXCEPT
|
||||
{
|
||||
return numRead != 0 || numWritten != 0;
|
||||
}
|
||||
constexpr bool operator !() const MIJIN_NOEXCEPT
|
||||
{
|
||||
return !static_cast<bool>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename TFrom, typename TTo>
|
||||
ConvertCharTypeResult convertCharType(const TFrom* chrFrom, std::size_t numFrom, TTo* outTo, std::size_t numTo, std::mbstate_t& mbstate) MIJIN_NOEXCEPT
|
||||
{
|
||||
if constexpr (std::is_same_v<TFrom, char>)
|
||||
{
|
||||
if constexpr (std::is_same_v<TTo, wchar_t>)
|
||||
{
|
||||
const std::size_t result = std::mbrtowc(outTo, chrFrom, numFrom, &mbstate);
|
||||
if (result == static_cast<std::size_t>(-1))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
.numRead = static_cast<unsigned>(result),
|
||||
.numWritten = 1
|
||||
};
|
||||
}
|
||||
if constexpr (std::is_same_v<TTo, char8_t>)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
if constexpr (std::is_same_v<TFrom, wchar_t>)
|
||||
{
|
||||
if constexpr (std::is_same_v<TTo, char>)
|
||||
{
|
||||
if (numTo < MB_CUR_MAX)
|
||||
{
|
||||
char tmpBuf[MB_LEN_MAX];
|
||||
const ConvertCharTypeResult result = convertCharType(chrFrom, tmpBuf, mbstate);
|
||||
if (result && result.numWritten <= numTo)
|
||||
{
|
||||
std::memcpy(outTo, tmpBuf, result.numWritten);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const std::size_t result = std::wcrtomb(outTo, *chrFrom, &mbstate);
|
||||
if (result == static_cast<std::size_t>(-1))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
.numRead = 1,
|
||||
.numWritten = static_cast<unsigned>(result)
|
||||
};
|
||||
}
|
||||
if constexpr (std::is_same_v<TTo, char8_t>)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
if constexpr (std::is_same_v<TFrom, char8_t>)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
template<typename TFrom, typename TTo>
|
||||
ConvertCharTypeResult convertCharType(const TFrom* chrFrom, std::size_t numFrom, TTo* outTo, std::size_t numTo) MIJIN_NOEXCEPT
|
||||
{
|
||||
std::mbstate_t mbstate;
|
||||
return convertCharType(chrFrom, numFrom, outTo, numTo, mbstate);
|
||||
}
|
||||
|
||||
template<typename TIterator>
|
||||
struct [[nodiscard]] ConvertStringTypeResult
|
||||
{
|
||||
TIterator iterator;
|
||||
bool success;
|
||||
};
|
||||
|
||||
template<typename TTo, typename TFrom, typename TFromTraits, std::output_iterator<TTo> TIterator>
|
||||
ConvertStringTypeResult<TIterator> convertStringType(std::basic_string_view<TFrom, TFromTraits> strFrom, TIterator outIterator)
|
||||
{
|
||||
TTo outBuffer[MB_LEN_MAX];
|
||||
|
||||
std::mbstate_t mbstate = {};
|
||||
for (auto it = strFrom.begin(); it != strFrom.end();)
|
||||
{
|
||||
const std::size_t remaining = std::distance(it, strFrom.end());
|
||||
const ConvertCharTypeResult result = convertCharType(&*it, remaining, outBuffer, MB_LEN_MAX, mbstate);
|
||||
if (!result)
|
||||
{
|
||||
return {
|
||||
.iterator = outIterator,
|
||||
.success = false
|
||||
};
|
||||
}
|
||||
for (unsigned pos = 0; pos < result.numWritten; ++pos)
|
||||
{
|
||||
*outIterator = outBuffer[pos];
|
||||
++outIterator;
|
||||
}
|
||||
it = std::next(it, result.numRead);
|
||||
}
|
||||
|
||||
return {
|
||||
.iterator = outIterator,
|
||||
.success = true
|
||||
};
|
||||
}
|
||||
|
||||
template<typename TFrom, typename TFromTraits, typename TTo, typename TToTraits, typename TToAllocator>
|
||||
bool convertStringType(std::basic_string_view<TFrom, TFromTraits> strFrom, std::basic_string<TTo, TToTraits, TToAllocator>& outString)
|
||||
{
|
||||
if constexpr (std::is_same_v<TTo, TFrom>)
|
||||
{
|
||||
outString += strFrom;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return convertStringType<TTo>(strFrom, std::back_inserter(outString)).success;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TFrom, typename TTo, typename TToTraits, typename TToAllocator>
|
||||
bool convertStringType(const TFrom* strFrom, std::basic_string<TTo, TToTraits, TToAllocator>& outString)
|
||||
{
|
||||
return convertStringType(std::basic_string_view<TFrom>(strFrom), outString);
|
||||
}
|
||||
} // namespace mijin
|
||||
|
||||
|
||||
Reference in New Issue
Block a user