#pragma once #include #include #include namespace ksys::util { // https://stackoverflow.com/a/53190503/1636285 struct concat_op {}; template struct FixedString { constexpr static std::size_t length() { return N; } constexpr static std::size_t capacity() { return N + 1; } template constexpr FixedString(concat_op, FixedString l, FixedString r) : FixedString() { static_assert(L + R == N); overwrite(0, l.data(), L); overwrite(L, r.data(), R); } constexpr FixedString() : buffer_{} {} constexpr FixedString(const char (&source)[N + 1]) : FixedString() { do_copy(source, buffer_.data()); } constexpr const char* data() const { return buffer_.data(); } constexpr char* data() { return buffer_.data(); } private: static constexpr void do_copy(const char (&source)[N + 1], char* dest) { for (std::size_t i = 0; i < capacity(); ++i) dest[i] = source[i]; } constexpr void overwrite(std::size_t where, const char* source, std::size_t len) { auto dest = buffer_.data() + where; while (len--) *dest++ = *source++; } std::array buffer_; }; template constexpr FixedString Str(const char (&c)[N]) { return FixedString(c); } template constexpr auto Str() { constexpr char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; constexpr auto len = [] { unsigned int len = N > 0 ? 0 : 1; for (auto n = N; n; len++, n /= base) continue; return len; }(); FixedString buf{}; auto ptr = buf.data() + buf.length(); if (N == 0) { buf.data()[0] = '0'; } else { for (auto n = N; n; n /= base) *--ptr = digits[(N < 0 ? -1 : 1) * (n % base)]; if (N < 0) *--ptr = '-'; } return buf; } template constexpr auto operator+(FixedString l, FixedString r) -> FixedString { auto result = FixedString(concat_op(), l, r); return result; } /// Takes any expression that returns a FixedString and returns a const char*. #define KSYS_STR(STR) \ ([]() -> const char* { \ using ksys::util::Str; \ static constexpr auto x = STR; \ return x.data(); \ }()) } // namespace ksys::util