Created
June 24, 2019 01:33
-
-
Save notfoundry/64782aacb650533e6d2563ab3f5a7fdb to your computer and use it in GitHub Desktop.
Align raw string literals to a common baseline at compiletime
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <cstdlib> | |
| #include <array> | |
| #include <boost/mp11/list.hpp> | |
| #include <boost/mp11/algorithm.hpp> | |
| using namespace boost::mp11; | |
| template <class C, C... Cs> | |
| struct nttp_string {}; | |
| template <class String, class Acc, class Splits> | |
| struct nttp_string_splitlines; | |
| template <class C, C... String, C... Acc, template <class...> class SplitsC, class... Splits> | |
| struct nttp_string_splitlines<nttp_string<C, C('\n'), String...>, nttp_string<C, Acc...>, SplitsC<Splits...>> { | |
| using type = typename nttp_string_splitlines< | |
| nttp_string<C, String...>, nttp_string<C>, SplitsC<Splits..., nttp_string<C, Acc...>> | |
| >::type; | |
| }; | |
| template <class C, C Front, C... String, C... Acc, class Splits> | |
| struct nttp_string_splitlines<nttp_string<C, Front, String...>, nttp_string<C, Acc...>, Splits> { | |
| using type = typename nttp_string_splitlines< | |
| nttp_string<C, String...>, nttp_string<C, Acc..., Front>, Splits | |
| >::type; | |
| }; | |
| template <class C, C... Acc, template <class...> class SplitsC, class... Splits> | |
| struct nttp_string_splitlines<nttp_string<C>, nttp_string<C, Acc...>, SplitsC<Splits...>> { | |
| using type = SplitsC<Splits..., nttp_string<C, Acc...>>; | |
| }; | |
| template <class Splits, class Acc> | |
| struct nttp_string_joinlines { | |
| using type = Acc; | |
| }; | |
| template <template <class...> class SplitsC, class C, C... Cs, class... Splits, C... Acc> | |
| struct nttp_string_joinlines<SplitsC<nttp_string<C, Cs...>, Splits...>, nttp_string<C, Acc...>> { | |
| using type = typename nttp_string_joinlines<SplitsC<Splits...>, nttp_string<C, Acc..., C('\n'), Cs...>>::type; | |
| }; | |
| template <std::size_t Count, class C, C Front, C... Rest> | |
| struct nttp_string_drop_impl { | |
| using type = typename nttp_string_drop_impl<Count - 1, C, Rest...>::type; | |
| }; | |
| template <class C, C Front, C... Cs> | |
| struct nttp_string_drop_impl<0, C, Front, Cs...> { | |
| using type = nttp_string<C, Front, Cs...>; | |
| }; | |
| template <std::size_t Count, class From> | |
| struct nttp_string_drop; | |
| template <std::size_t Count, class C, C... Cs> | |
| struct nttp_string_drop<Count, nttp_string<C, Cs...>> { | |
| using type = typename nttp_string_drop_impl<Count, C, Cs...>::type; | |
| }; | |
| template <class From, std::size_t Acc = 0> | |
| struct get_indent; | |
| template <class C, C... From, std::size_t Acc> | |
| struct get_indent<nttp_string<C, C(' '), From...>, Acc> { | |
| constexpr static std::size_t value = get_indent<nttp_string<C, From...>, Acc + 1>::value; | |
| }; | |
| template <class C, C... FromCs, std::size_t Acc> | |
| struct get_indent<nttp_string<C, FromCs...>, Acc> { | |
| constexpr static std::size_t value = Acc; | |
| }; | |
| template <class S> | |
| struct nttp_string_to_cstring; | |
| template <class C, C... Cs> | |
| struct nttp_string_to_cstring<nttp_string<C, Cs...>> { | |
| constexpr static std::array<C, sizeof...(Cs)> data {Cs...}; | |
| constexpr static C const* value = data.data(); | |
| }; | |
| template <class C, C... Cs> | |
| struct align_impl { | |
| using split = typename nttp_string_splitlines<nttp_string<C, Cs...>, nttp_string<C>, mp_list<>>::type; | |
| using front = mp_front<split>; | |
| using rest = mp_pop_front<split>; | |
| constexpr static std::size_t indent = get_indent<mp_front<rest>>::value; | |
| template <class From> | |
| using strip_indent = typename nttp_string_drop<indent, From>::type; | |
| using stripped_rest = mp_transform<strip_indent, rest>; | |
| using nttp_value = typename nttp_string_joinlines<stripped_rest, front>::type; | |
| constexpr static C const* value = nttp_string_to_cstring<nttp_value>::value; | |
| }; | |
| template <class C, C... Cs> | |
| constexpr auto operator""_align() noexcept { | |
| return align_impl<C, Cs...>::value; | |
| } | |
| // let's try it out | |
| auto source = R"(for x in [1, 2, 3]: | |
| squared = x * x | |
| for y in range(squared): | |
| print(y))"_align; | |
| auto expected_output = R"(0 | |
| 01 | |
| 012 | |
| 0123 | |
| 01234 | |
| 012345 | |
| 0123456 | |
| 01234567 | |
| 012345678 | |
| 0123456789)"_align; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment