aboutsummaryrefslogtreecommitdiffstats
path: root/f_to_string.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'f_to_string.hpp')
-rw-r--r--f_to_string.hpp90
1 files changed, 90 insertions, 0 deletions
diff --git a/f_to_string.hpp b/f_to_string.hpp
new file mode 100644
index 0000000..8b91a90
--- /dev/null
+++ b/f_to_string.hpp
@@ -0,0 +1,90 @@
+/**
+ * f_to_string.hpp - Provides compile-time floating-point-to-string conversion.
+ * Written by Clyne Sullivan.
+ * https://github.com/tcsullivan/constexpr-to-string
+ */
+
+#ifndef TCSULLIVAN_F_TO_STRING_HPP_
+#define TCSULLIVAN_F_TO_STRING_HPP_
+
+struct f_to_string_double_wrapper {
+ long long int whole = 0;
+ long long int frac = 0;
+
+ constexpr f_to_string_double_wrapper(double v, int prec = 5) {
+ whole = static_cast<long long int>(v);
+ v -= whole;
+ for (int i = 0; i < prec; i++)
+ v *= 10;
+ frac = static_cast<long long int>(v);
+ }
+};
+
+/**
+ * @struct f_to_string_t
+ * @brief Provides the ability to convert a floating-point number to a string at compile-time.
+ * @tparam N Number to convert
+ */
+template<f_to_string_double_wrapper N, typename char_type>
+class f_to_string_t {
+ char_type buf[([]() constexpr noexcept {
+ unsigned int len = 2;
+ if (N.whole <= 0) len++;
+ for (auto n = N.whole; n; len++, n /= 10);
+ if (N.frac == 0 || (N.whole == 0 && N.frac < 0)) len++;
+ for (auto n = N.frac; n; len++, n /= 10);
+ return len;
+ }())] = {};
+
+ public:
+ /**
+ * Constructs the object, filling `buf` with the string representation of N.
+ */
+ constexpr f_to_string_t() noexcept {
+ auto append = [](auto V, auto& ptr) {
+ if (V != 0) {
+ for (auto n = V; n; n /= 10)
+ *--ptr = (V < 0 ? -1 : 1) * (n % 10) + '0';
+ } else {
+ *--ptr = '0';
+ }
+ };
+
+ auto ptr = end();
+ *--ptr = '\0';
+ append(N.frac, ptr);
+ *--ptr = '.';
+ append(N.whole, ptr);
+ if (N.frac < 0 || N.whole < 0)
+ *--ptr = '-';
+ }
+
+ // Support implicit casting to `char *` or `const char *`.
+ constexpr operator char_type *() noexcept { return buf; }
+ constexpr operator const char_type *() const noexcept { return buf; }
+
+ constexpr auto size() const noexcept { return sizeof(buf) / sizeof(buf[0]); }
+ // Element access
+ constexpr auto data() noexcept { return buf; }
+ constexpr const auto data() const noexcept { return buf; }
+ constexpr auto& operator[](unsigned int i) noexcept { return buf[i]; }
+ constexpr const auto& operator[](unsigned int i) const noexcept { return buf[i]; }
+ constexpr auto& front() noexcept { return buf[0]; }
+ constexpr const auto& front() const noexcept { return buf[0]; }
+ constexpr auto& back() noexcept { return buf[size() - 1]; }
+ constexpr const auto& back() const noexcept { return buf[size() - 1]; }
+ // Iterators
+ constexpr auto begin() noexcept { return buf; }
+ constexpr const auto begin() const noexcept { return buf; }
+ constexpr auto end() noexcept { return buf + size(); }
+ constexpr const auto end() const noexcept { return buf + size(); }
+};
+
+/**
+ * Simplifies use of `f_to_string_t` from `f_to_string_t<N>()` to `f_to_string<N>`.
+ */
+template<f_to_string_double_wrapper N, typename char_type = char>
+constexpr f_to_string_t<N, char_type> f_to_string;
+
+#endif // TCSULLIVAN_F_TO_STRING_HPP_
+