Add support for constexpr string_view creation

This commit is contained in:
King_DuckZ 2021-05-28 02:06:28 +02:00
parent e62da38cf9
commit 422b475ce3
3 changed files with 74 additions and 21 deletions

View file

@ -168,6 +168,9 @@ namespace dhandy {
}
};
template <typename I, I In, unsigned int Base, typename Tr>
inline constexpr const auto g_int_to_str = IntConversion<std::remove_cvref_t<I>, Base, Tr>::to_ary(In);
template <typename T>
[[gnu::always_inline,gnu::pure]]
constexpr inline T negated_ifn (T n, bool negate) {
@ -293,6 +296,11 @@ namespace dhandy {
template <typename C>
using ASCIITranslatorUpcase = ASCIITranslator<C, '0', 'A'>;
template <typename I, I In, unsigned int Base=10, typename Tr=ASCIITranslator<char>>
constexpr inline const auto& buildtime_int_to_ary() {
return implem::g_int_to_str<I, In, Base, Tr>;
}
template <typename I, unsigned int Base=10, typename Tr=ASCIITranslator<char>>
constexpr inline auto int_to_ary (I in) {
return implem::IntConversion<std::remove_cvref_t<I>, Base, Tr>::to_ary(in);

View file

@ -26,47 +26,68 @@
namespace dhandy {
namespace implem {
template <typename T, typename F, bool SafeRetval>
template <typename T, typename F, bool SafeRetval, typename Tr>
struct IntConv;
template <typename F, bool SafeRetval>
struct IntConv<std::enable_if_t<std::is_integral_v<F>, std::string>, F, SafeRetval> {
static std::string conv (const F& in) {
auto retval = dhandy::int_to_ary(in);
return std::string(retval.begin(), retval.end() - 1);
template <typename Tr>
using IntConvString = std::basic_string<typename Tr::char_type>;
template <typename Tr>
using IntConvStringView = std::basic_string_view<typename Tr::char_type>;
template <typename F, bool SafeRetval, typename Tr>
struct IntConv<std::enable_if_t<std::is_integral_v<F>, IntConvString<Tr>>, F, SafeRetval, Tr> {
static IntConvString<Tr> conv (const F& in) {
auto retval = dhandy::int_to_ary<F, 10, Tr>(in);
return IntConvString<Tr>{retval.begin(), retval.end() - 1};
}
};
template <typename F, bool SafeRetval>
struct IntConv<std::enable_if_t<std::is_integral_v<F>, std::string_view>, F, SafeRetval> {
constexpr static std::string_view conv (const F& in) {
template <typename F, bool SafeRetval, typename Tr>
struct IntConv<std::enable_if_t<std::is_integral_v<F>, IntConvStringView<Tr>>, F, SafeRetval, Tr> {
constexpr static IntConvStringView<Tr> conv (const F& in) {
if (std::is_constant_evaluated() or not SafeRetval)
return dhandy::int_to_ary(in).to_string_view();
return dhandy::int_to_ary<F, 10, Tr>(in).to_string_view();
else
throw std::logic_error("Only callable in a constexpr context, call int_conv_temporary() instead if you know what you're doing");
}
};
template <typename T, bool SafeRetval>
struct IntConv<T, std::enable_if_t<std::is_integral_v<T>, std::string>, SafeRetval> {
constexpr static T conv (const std::string& in) {
return dhandy::ary_to_int<T>(in.data(), in.data() + in.size());
template <typename T, bool SafeRetval, typename Tr>
struct IntConv<T, std::enable_if_t<std::is_integral_v<T>, IntConvString<Tr>>, SafeRetval, Tr> {
constexpr static T conv (const IntConvString<Tr>& in) {
return dhandy::ary_to_int<T, char, 10, Tr>(
in.data(),
in.data() + in.size()
);
}
};
template <typename T, bool SafeRetval>
struct IntConv<T, std::enable_if_t<std::is_integral_v<T>, std::string_view>, SafeRetval> {
constexpr static T conv (const std::string_view& in) {
return dhandy::ary_to_int<T>(in.data(), in.data() + in.size());
template <typename T, bool SafeRetval, typename Tr>
struct IntConv<T, std::enable_if_t<std::is_integral_v<T>, IntConvStringView<Tr>>, SafeRetval, Tr> {
constexpr static T conv (const IntConvStringView<Tr>& in) {
return dhandy::ary_to_int<T, char, 10, Tr>(
in.data(),
in.data() + in.size()
);
}
};
template <typename T, typename F, F In, bool SafeRetval, typename Tr>
struct IntConv<T, std::integral_constant<F, In>, SafeRetval, Tr> {
constexpr static T conv (const std::integral_constant<F, In>&) {
return dhandy::buildtime_int_to_ary<F, In, 10, Tr>().to_string_view();
}
};
} //namespace implem
template <typename To, typename From>
constexpr inline To int_conv (const From& from) {
return implem::IntConv<To, From, true>::conv(from);
constexpr inline To int_conv (const From& from, bool all_caps=false) {
if (all_caps)
return implem::IntConv<To, From, true, ASCIITranslatorUpcase<char>>::conv(from);
else
return implem::IntConv<To, From, true, ASCIITranslator<char>>::conv(from);
}
template <typename To, typename From>
constexpr inline To int_conv_temporary (const From& from) {
return implem::IntConv<To, From, false>::conv(from);
return implem::IntConv<To, From, false, ASCIITranslator<char>>::conv(from);
}
} //namespace dhandy

View file

@ -171,3 +171,27 @@ TEST_CASE ("Check char array to int conversions", "[i2s][int_conv]") {
AryConversionTestHelper<std::int64_t, 10>("-1", -1, false);
AryConversionTestHelper<std::int64_t, 10>("-510123123123", -510123123123, false);
}
TEST_CASE ("Check upcase/downcase int to array conversions", "[i2s][int_conv]") {
using dhandy::int_conv;
using std::string_view;
using std::integral_constant;
constexpr auto bool1 = int_conv<string_view>(integral_constant<bool, true>{});
CHECK("1" == bool1);
constexpr auto bool2 = int_conv<string_view>(integral_constant<bool, false>{});
CHECK("0" == bool2);
constexpr auto int1 = int_conv<string_view>(integral_constant<int, 42>{});
CHECK("42" == int1);
constexpr auto int2 = int_conv<string_view>(integral_constant<unsigned int, 7777777>{});
CHECK("7777777" == int2);
constexpr auto int3 = int_conv<string_view>(integral_constant<int, -1234>{});
CHECK("-1234" == int3);
constexpr auto int4 = int_conv<string_view>(integral_constant<short int, -256>{});
CHECK("-256" == int4);
}