]> code.bitgloo.com Git - clyne/constexpr-to-string.git/commitdiff
added f_to_string
authorClyne Sullivan <clyne@bitgloo.com>
Sun, 28 Jun 2020 13:20:12 +0000 (09:20 -0400)
committerClyne Sullivan <clyne@bitgloo.com>
Sun, 28 Jun 2020 13:20:12 +0000 (09:20 -0400)
f_to_string.hpp [new file with mode: 0644]

diff --git a/f_to_string.hpp b/f_to_string.hpp
new file mode 100644 (file)
index 0000000..3d0fd18
--- /dev/null
@@ -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 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[(V < 0 ? -1 : 1) * (n % 10)];
+            } 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_
+