aboutsummaryrefslogtreecommitdiffstats
path: root/to_string.hpp
blob: 2d185899a912c2f4da7469e1d66d47c97660aa04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**
 * to_string.hpp - Provides compile-time integer-to-string conversion.
 * Written by Clyne Sullivan.
 * https://github.com/tcsullivan/constexpr-to-string
 */

#ifndef TCSULLIVAN_TO_STRING_HPP_
#define TCSULLIVAN_TO_STRING_HPP_

#include <type_traits>

constexpr char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
constexpr auto digit_count = sizeof(digits) / sizeof(digits[0]);

/**
 * @struct to_string_t
 * @brief Provides the ability to convert any integral to a string at compile-time.
 * @tparam N Number to convert
 * @tparam base Desired base, can be from 2 to 36
 */
template<auto N, unsigned int base, typename char_type,
    std::enable_if_t<std::is_integral_v<decltype(N)>, int> = 0,
    std::enable_if_t<(base > 1 && base < digit_count), int> = 0>
struct to_string_t {
    // The lambda calculates what the string length of N will be, so that `buf`
    // fits to the number perfectly.
    char_type buf[([] {
                       unsigned int len = N > 0 ? 1 : 2;
                       for (auto n = N < 0 ? -N : N; n; len++, n /= base);
                       return len;
                   }())] = {};

    /**
     * Constructs the object, filling `buf` with the string representation of N.
     */
    constexpr to_string_t() noexcept {
        if (N != 0) {
            auto ptr = buf + sizeof(buf) / sizeof(buf[0]);
            *--ptr = '\0';
            for (auto n = N < 0 ? -N : N; n; n /= base)
                *--ptr = digits[n % base];
            if (N < 0)
                *--ptr = '-';
        } else {
            buf[0] = '0';
        }
    }

    // Support implicit casting to `char *` or `const char *`.
    constexpr operator char_type *() { return buf; }
    constexpr operator const char_type *() const { return buf; }
    
    // Support range-based for loops
    constexpr auto begin() { return buf; }
    constexpr auto begin() const { return buf; }
    constexpr auto end() { return buf + sizeof(buf) / sizeof(buf[0]); }
    constexpr auto end() const { return buf + sizeof(buf) / sizeof(buf[0]); }
};

/**
 * Simplifies use of `to_string_t` from `to_string_t<N>()` to `to_string<N>`.
 */
template<auto N, unsigned int base = 10, typename char_type = char>
constexpr to_string_t<N, base, char_type> to_string;
 
#endif // TCSULLIVAN_TO_STRING_HPP_