diff options
| -rw-r--r-- | cxxformat.hpp | 62 | ||||
| -rw-r--r-- | main.cpp | 9 |
2 files changed, 46 insertions, 25 deletions
diff --git a/cxxformat.hpp b/cxxformat.hpp index 6a86e4c..1dd919e 100644 --- a/cxxformat.hpp +++ b/cxxformat.hpp @@ -411,34 +411,51 @@ private: template<size_t... indices> constexpr str<N + 1> appendCharHelper(const char c, std::index_sequence<indices...>) const { - return str<N + 1>{s[indices]..., c, '\0'}; + return str<N + 1>{s[indices]..., c}; } template<size_t... indices> static constexpr str<N + 1> prependCharHelper(const char c, const str<N> &s, std::index_sequence<indices...>) { - return str<N + 1>{c, s.s[indices]..., '\0'}; + return str<N + 1>{c, s.s[indices]...}; } template<auto other, size_t... ownIndices, size_t... othersIndices> constexpr str<N + sizeof...(othersIndices)> appendStrHelper(std::index_sequence<ownIndices...>, std::index_sequence<othersIndices...>) const { - return str<N + sizeof...(othersIndices)>{s[ownIndices]..., other.s[othersIndices]..., '\0'}; + return str<N + sizeof...(othersIndices)>{s[ownIndices]..., other.s[othersIndices]...}; } + public: + template<size_t... indices> + constexpr str(const char (&s)[N + 1], std::index_sequence<indices...>) : s{s[indices]...} + { + + } + + constexpr str(const char (&s)[N + 1]) : str{s, std::make_index_sequence<N + 1>()} + { + + } + + template<typename... Chars> + constexpr str(Chars... chars) : s{chars..., '\0'} + { + static_assert(N == sizeof...(chars), "O.o"); + } template<size_t index> - constexpr char get(str_index<index>) const + constexpr char get() const { static_assert(index < N, "str::get: index out of range"); return s[index]; } template<size_t offset, size_t... indices> - constexpr str<sizeof...(indices)> extract(std::index_sequence<indices...>, str_index<offset> = str_index<0>{}) const + constexpr str<sizeof...(indices)> extract(std::index_sequence<indices...>) const { static_assert(((indices + offset < N) && ...), "str::extract: index out of range"); - return str<sizeof...(indices)>{s[indices + offset]..., '\0'}; + return str<sizeof...(indices)>{s[indices + offset]...}; } constexpr str<N + 1> operator+(const char c) const @@ -465,28 +482,31 @@ constexpr str<N + 1> operator+(const char c, const str<N> &other) template<size_t N> str(const char(&)[N]) -> str<N - 1>; +template<typename... Chars> +str(Chars... chars) -> str<sizeof...(Chars)>; + namespace detail { template<size_t i, size_t N> constexpr char get(const str<N>& s) { - return s.get(str_index<i>{}); + return s.template get<i>(); } template<size_t N, size_t offset, size_t... indices> constexpr str<sizeof...(indices)> extractStr(const str<N> &source, std::index_sequence<indices...>) { - return str<sizeof...(indices)>{get<indices + offset>(source)..., '\0'}; + return str<sizeof...(indices)>{get<indices + offset>(source)...}; } template<size_t start, size_t end = std::string::npos, bool endIsIndex = false, size_t N> constexpr str<end == std::string::npos ? N - start : (endIsIndex ? end + 1 - start : end)> substr(const str<N> &s) { - static_assert(!endIsIndex || end < N, "End index / substr-length is out of range"); - if constexpr (end == std::string::npos) return substr<start, N - 1, true>(s); + static_assert(!endIsIndex || end < N, "substr: end index / substr-length is out of range"); + if constexpr (!endIsIndex && end == 0) return str<0>{}; + else if constexpr (end == std::string::npos) return substr<start, N - 1, true>(s); else if constexpr (!endIsIndex) return substr<start, start + end - 1, true>(s); - else if constexpr (endIsIndex && end + 1 - start == 0) return str{""}; - else return s.extract(std::make_index_sequence<end - start + 1>(), str_index<start>{}); + else return s.template extract<start>(std::make_index_sequence<end - start + 1>()); } template<typename T, auto s, size_t i = 0, bool allowSign = true, T parsedPart = 0> @@ -532,7 +552,7 @@ namespace detail return str<1>{'0' + N}; } else return toStr<T, N / 10>() + char(N % 10 + '0'); - }; + } template<auto fmt, size_t i, size_t argumentIndex> std::string format_s() @@ -608,15 +628,15 @@ namespace detail constexpr char conversion = checkReplaceAutoConversion<get<iAfterPrecision>(fmt), argumentIndex>(std::forward<Arg>(arg)); - if constexpr (conversion == 'c') return substr<0, i - 1, true>(fmt).s + strprintf(makeDirective<fmt, conversion, i, iAfterPrecision, 0>().s, convert<char, false>(std::forward<Arg>(arg), "character", argumentIndex)) + format_s<substr<iAfterPrecision + 1>(fmt), 0, argumentIndex + 1>(std::forward<Args>(args)...); - else if constexpr (conversion == 'd' || conversion == 'i') return substr<0, i - 1, true>(fmt).s + strprintf(makeDirective<fmt, conversion, i, iAfterPrecision, 'j'>().s, convert<std::intmax_t, false>(std::forward<Arg>(arg), "signed integer", argumentIndex)) + format_s<substr<iAfterPrecision + 1>(fmt), 0, argumentIndex + 1>(std::forward<Args>(args)...); - else if constexpr (conversion == 'u' || conversion == 'o' || conversion == 'x' || conversion == 'X') return substr<0, i - 1, true>(fmt).s + strprintf(makeDirective<fmt, conversion, i, iAfterPrecision, 'j'>().s, convert<std::uintmax_t, false>(std::forward<Arg>(arg), "unsigned integer", argumentIndex)) + format_s<substr<iAfterPrecision + 1>(fmt), 0, argumentIndex + 1>(std::forward<Args>(args)...); - else if constexpr (conversion == 'e' || conversion == 'E' || conversion == 'f' || conversion == 'F' || conversion == 'g' || conversion == 'G' || conversion == 'a' || conversion == 'A') return substr<0, i - 1, true>(fmt).s + strprintf(makeDirective<fmt, conversion, i, iAfterPrecision, 0>().s, convert<double, false>(std::forward<Arg>(arg), "double", argumentIndex)) + format_s<substr<iAfterPrecision + 1>(fmt), 0, argumentIndex + 1>(std::forward<Args>(args)...); - else if constexpr (conversion == 'p') return substr<0, i - 1, true>(fmt).s + strprintf(makeDirective<fmt, conversion, i, iAfterPrecision, 0>().s, convert<const void *, false>(std::forward<Arg>(arg), "pointer", argumentIndex)) + format_s<substr<iAfterPrecision + 1>(fmt), 0, argumentIndex + 1>(std::forward<Args>(args)...); + if constexpr (conversion == 'c') return substr<0, i>(fmt).s + strprintf(makeDirective<fmt, conversion, i, iAfterPrecision, 0>().s, convert<char, false>(std::forward<Arg>(arg), "character", argumentIndex)) + format_s<substr<iAfterPrecision + 1>(fmt), 0, argumentIndex + 1>(std::forward<Args>(args)...); + else if constexpr (conversion == 'd' || conversion == 'i') return substr<0, i>(fmt).s + strprintf(makeDirective<fmt, conversion, i, iAfterPrecision, 'j'>().s, convert<std::intmax_t, false>(std::forward<Arg>(arg), "signed integer", argumentIndex)) + format_s<substr<iAfterPrecision + 1>(fmt), 0, argumentIndex + 1>(std::forward<Args>(args)...); + else if constexpr (conversion == 'u' || conversion == 'o' || conversion == 'x' || conversion == 'X') return substr<0, i>(fmt).s + strprintf(makeDirective<fmt, conversion, i, iAfterPrecision, 'j'>().s, convert<std::uintmax_t, false>(std::forward<Arg>(arg), "unsigned integer", argumentIndex)) + format_s<substr<iAfterPrecision + 1>(fmt), 0, argumentIndex + 1>(std::forward<Args>(args)...); + else if constexpr (conversion == 'e' || conversion == 'E' || conversion == 'f' || conversion == 'F' || conversion == 'g' || conversion == 'G' || conversion == 'a' || conversion == 'A') return substr<0, i>(fmt).s + strprintf(makeDirective<fmt, conversion, i, iAfterPrecision, 0>().s, convert<double, false>(std::forward<Arg>(arg), "double", argumentIndex)) + format_s<substr<iAfterPrecision + 1>(fmt), 0, argumentIndex + 1>(std::forward<Args>(args)...); + else if constexpr (conversion == 'p') return substr<0, i>(fmt).s + strprintf(makeDirective<fmt, conversion, i, iAfterPrecision, 0>().s, convert<const void *, false>(std::forward<Arg>(arg), "pointer", argumentIndex)) + format_s<substr<iAfterPrecision + 1>(fmt), 0, argumentIndex + 1>(std::forward<Args>(args)...); else if constexpr (conversion == 's') { const auto& string = convert<string_or_string_view<remove_cvref_t<Arg>>, false>(std::forward<Arg>(arg), "string", argumentIndex); - return substr<0, i - 1, true>(fmt).s + strprintf((str{"%."}.s + std::to_string(determineStringPrecision<havePrecision, fmt, iAfterFieldWidth, iAfterPrecision>(string)) + 's').c_str(), string.data()) + format_s<substr<iAfterPrecision + 1>(fmt), 0, argumentIndex + 1>(std::forward<Args>(args)...); + return substr<0, i>(fmt).s + strprintf((str{"%."}.s + std::to_string(determineStringPrecision<havePrecision, fmt, iAfterFieldWidth, iAfterPrecision>(string)) + 's').c_str(), string.data()) + format_s<substr<iAfterPrecision + 1>(fmt), 0, argumentIndex + 1>(std::forward<Args>(args)...); } else { @@ -628,8 +648,8 @@ namespace detail } } -template<auto fmt, typename... Args> -std::string format_s(Args &&...args) +template<str fmt, typename... Args> +std::string format(Args &&...args) { return detail::format_s<fmt, 0, 1>(std::forward<Args>(args)...); } @@ -40,11 +40,12 @@ struct format::AutoConversion<std::array<T, N>> : format::SimpleAutoConversion<' template<size_t N, typename T> struct format::AutoConversion<T[N], std::enable_if_t<!std::is_same_v<format::detail::remove_cvref_t<T>, char>>> : format::SimpleAutoConversion<'s', const T(&)[N]> {}; -int main(int argc, char *argv[]) +int main(int, char *[]) { - const std::array<int, 5> array[] = {std::array{1, 2, 3, 4, 5}, std::array{1, 2, 3, 4, 5}, std::array{1, 2, 3, 4, 5}, std::array{1, 2, 3, 4, 5}, std::array{1, 2, 3, 4, 5}}; - std::cout << format::format_s<format::str{"Hello %s: %d %03.5f %V"}>("World", 7, 3.5, &array) << std::endl; - std::cout << format::format("%v%v%v%v%v", 'H', 'e', 'l', 'l', 'o') << std::endl; + constexpr std::array<int, 5> array[] = {std::array{1, 2, 3, 4, 5}, std::array{1, 2, 3, 4, 5}, std::array{1, 2, 3, 4, 5}, std::array{1, 2, 3, 4, 5}, std::array{1, 2, 3, 4, 5}}; + + std::cout << format::format<"Hello %s: %d %03.5f %V">("World", 7, 3.5, array) << std::endl; + std::cout << format::format<"%v%v%v%v%v">('H', 'e', 'l', 'l', 'o') << std::endl; std::cout << format::format("%V", &array) << std::endl; std::cout << format::format("%s", std::array{1, 2, 3, 4, 5}) << std::endl; std::cout << format::format("Hello %v: %-7v %v", "World", 3.5, 5) << std::endl; |
