Skip to content

Instantly share code, notes, and snippets.

@Sam-Belliveau
Created July 12, 2022 19:18
Show Gist options
  • Save Sam-Belliveau/a88739ed0c0c026f5b9dd95645a78086 to your computer and use it in GitHub Desktop.
Save Sam-Belliveau/a88739ed0c0c026f5b9dd95645a78086 to your computer and use it in GitHub Desktop.
Constant Expression Generation of Roman Numerals. Every roman numeral generated with this is a string literal, and can be used as such.
/**
* MIT License
*
* Copyright (c) 2022 Sam Belliveau
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef ROMAN_NUMERALS_HPP
#define ROMAN_NUMERALS_HPP 1
#include <cstdint>
#include <array>
namespace roman
{
template<std::size_t N>
struct base : public base<N-1> {};
#define ROMAN_NUMERALS_MAKE_BASE(N, T) \
template<> \
struct base<N> \
{ \
static constexpr std::size_t value{N}; \
static constexpr std::size_t size{sizeof(T)}; \
static constexpr std::array<char, size> letters{T}; \
static constexpr char const* text{T}; \
};
ROMAN_NUMERALS_MAKE_BASE(1, "I")
ROMAN_NUMERALS_MAKE_BASE(4, "IV")
ROMAN_NUMERALS_MAKE_BASE(5, "V")
ROMAN_NUMERALS_MAKE_BASE(9, "IX")
ROMAN_NUMERALS_MAKE_BASE(10, "X")
ROMAN_NUMERALS_MAKE_BASE(40, "XL")
ROMAN_NUMERALS_MAKE_BASE(50, "L")
ROMAN_NUMERALS_MAKE_BASE(90, "XC")
ROMAN_NUMERALS_MAKE_BASE(100, "C")
ROMAN_NUMERALS_MAKE_BASE(400, "CD")
ROMAN_NUMERALS_MAKE_BASE(500, "D")
ROMAN_NUMERALS_MAKE_BASE(900, "CM")
ROMAN_NUMERALS_MAKE_BASE(1000, "M")
ROMAN_NUMERALS_MAKE_BASE(2000, "MM")
ROMAN_NUMERALS_MAKE_BASE(3000, "MMM")
#undef ROMAN_NUMERALS_MAKE_BASE
template <std::size_t N>
struct numeral
{
using MSD = base<N>;
using SUB = numeral<N - MSD::value>;
static constexpr std::size_t sizea = MSD::size - 1;
static constexpr std::size_t sizeb = SUB::size;
static constexpr std::size_t value = N;
static constexpr std::size_t size = sizea + sizeb;
using letters_t = std::array<char, size>;
static constexpr letters_t concat() {
letters_t c{};
for(std::size_t i = 0; i < sizea; ++i) c[00000 + i] = MSD::letters[i];
for(std::size_t i = 0; i < sizeb; ++i) c[sizea + i] = SUB::letters[i];
return c;
}
static constexpr letters_t letters{concat()};
static constexpr char const* text{letters.data()};
};
template<>
struct numeral<0>
{
static constexpr std::size_t value = 0;
static constexpr std::size_t size = 1;
static constexpr std::array<char, 1> letters{'\0'};
static constexpr char const* text{letters.data()};
};
template<std::size_t N>
constexpr char const* numeral_t = numeral<N>::text;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment