From 86b427f334019e168c7959b75153f6c518c06983 Mon Sep 17 00:00:00 2001
From: Amelia Coutard <eliottulio.coutard@gmail.com>
Date: Sun, 16 Oct 2022 02:12:37 +0200
Subject: [PATCH] Made it so arg_n have to all be specified or all missing, no
 weird combining of the two. Also added convertion to a common type, to
 instanciate less occurences of print_nth_helper::operator%

---
 kernel/src/serial.cpp |  6 ------
 kernel/src/serial.hpp | 30 +++++++++++++++++++++++-------
 2 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/kernel/src/serial.cpp b/kernel/src/serial.cpp
index 8486245..e8d9ccf 100644
--- a/kernel/src/serial.cpp
+++ b/kernel/src/serial.cpp
@@ -62,12 +62,6 @@ void os::print_formatted(const char* format, std::int64_t val) {
 		os::print_formatted(format, std::uint64_t(val));
 	}
 }
-void os::print_formatted(const char* format, std::uint32_t val) { os::print_formatted(format, std::uint64_t(val)); }
-void os::print_formatted(const char* format, std::uint16_t val) { os::print_formatted(format, std::uint64_t(val)); }
-void os::print_formatted(const char* format, std::uint8_t val) { os::print_formatted(format, std::uint64_t(val)); }
-void os::print_formatted(const char* format, std::int32_t val) { os::print_formatted(format, std::int64_t(val)); }
-void os::print_formatted(const char* format, std::int16_t val) { os::print_formatted(format, std::int64_t(val)); }
-void os::print_formatted(const char* format, std::int8_t val) { os::print_formatted(format, std::int64_t(val)); }
 void os::assert(bool cond, const char* diagnostic) {
 	if (!cond) {
 		os::print("Error: {}\n", diagnostic);
diff --git a/kernel/src/serial.hpp b/kernel/src/serial.hpp
index 0aa0f2b..cbeb5a3 100644
--- a/kernel/src/serial.hpp
+++ b/kernel/src/serial.hpp
@@ -19,12 +19,18 @@ void printc(char c);
 void print_formatted(const char* format, const char* val);
 void print_formatted(const char* format, std::uint64_t val);
 void print_formatted(const char* format, std::int64_t val);
-void print_formatted(const char* format, std::uint32_t val);
-void print_formatted(const char* format, std::int32_t val);
-void print_formatted(const char* format, std::uint16_t val);
-void print_formatted(const char* format, std::int16_t val);
-void print_formatted(const char* format, std::uint8_t val);
-void print_formatted(const char* format, std::int8_t val);
+
+template <typename T_> struct get_more_general_type_helper {
+	using T = T_;
+};
+template <typename T> using get_more_general_type_helper_t = get_more_general_type_helper<T>::T;
+template <> struct get_more_general_type_helper<std::uint8_t> { using T = std::uint64_t; };
+template <> struct get_more_general_type_helper<std::uint16_t> { using T = std::uint64_t; };
+template <> struct get_more_general_type_helper<std::uint32_t> { using T = std::uint64_t; };
+template <> struct get_more_general_type_helper<std::int8_t> { using T = std::int64_t; };
+template <> struct get_more_general_type_helper<std::int16_t> { using T = std::int64_t; };
+template <> struct get_more_general_type_helper<std::int32_t> { using T = std::int64_t; };
+template <std::size_t n> struct get_more_general_type_helper<char[n]> { using T = const char*; };
 
 struct print_nth_helper {
 	std::size_t n;
@@ -43,6 +49,7 @@ struct print_nth_helper {
 template<typename... Ts>
 void print(const char* format, const Ts&... vs) {
 	std::size_t arg_n = 0;
+	bool arg_n_is_given = 0;
 	for (std::size_t i = 0; format[i] != '\0'; i++) {
 		if (format[i] == '{') {
 			i++;
@@ -60,11 +67,20 @@ void print(const char* format, const Ts&... vs) {
 				}
 				std::size_t n = arg_n;
 				if ('0' <= format[i] && format[i] <= '9') {
+					if (arg_n == 0) {
+						arg_n_is_given = true;
+					}
+					os::assert(arg_n_is_given, "Error in format string: either the arg_id is always given, or never.");
 					std::size_t n_ = 0;
 					while ('0' <= format[i] && format[i] <= '9') {
 						n_ = n_ * 10 + (format[i++] - '0');
 					}
 					n = n_;
+				} else {
+					if (arg_n == 0) {
+						arg_n_is_given = false;
+					}
+					os::assert(!arg_n_is_given, "Error in format string: either the arg_id is always given, or never.");
 				}
 				if (format[i] == ':') {
 					i++;
@@ -72,7 +88,7 @@ void print(const char* format, const Ts&... vs) {
 					os::assert(format[i] == '}', "Error in format string: ':' required before format spec.");
 				}
 				os::assert(n < sizeof...(vs), "Error in format string: not enough arguments.");
-				(print_nth_helper{n, &format[i]} % ... % vs);
+				(print_nth_helper{n, &format[i]} % ... % get_more_general_type_helper_t<Ts>(vs));
 				i = format_spec_end;
 				arg_n++;
 			}
-- 
2.46.0