fork(1) download
  1. // Jarod42.
  2.  
  3. #include <cstdint>
  4.  
  5. // Sequence of char
  6. template <char...Cs> struct char_sequence
  7. {
  8. template <char C> using push_back = char_sequence<Cs..., C>;
  9. };
  10.  
  11. // Remove all chars from char_sequence from '\0'
  12. template <typename, char...> struct strip_sequence;
  13.  
  14. template <char...Cs>
  15. struct strip_sequence<char_sequence<>, Cs...>
  16. {
  17. using type = char_sequence<Cs...>;
  18. };
  19.  
  20. template <char...Cs, char...Cs2>
  21. struct strip_sequence<char_sequence<'\0', Cs...>, Cs2...>
  22. {
  23. using type = char_sequence<Cs2...>;
  24. };
  25.  
  26. template <char...Cs, char C, char...Cs2>
  27. struct strip_sequence<char_sequence<C, Cs...>, Cs2...>
  28. {
  29. using type = typename strip_sequence<char_sequence<Cs...>, Cs2..., C>::type;
  30. };
  31.  
  32. // struct to create a aligned char array
  33. template <std::size_t Alignment, typename chars> struct aligned_string;
  34.  
  35. template <std::size_t Alignment, char...Cs>
  36. struct aligned_string<Alignment, char_sequence<Cs...>>
  37. {
  38. alignas(Alignment) static constexpr char str[sizeof...(Cs)] = {Cs...};
  39. };
  40.  
  41. template <std::size_t Alignment, char...Cs>
  42. alignas(Alignment) constexpr
  43. char aligned_string<Alignment, char_sequence<Cs...>>::str[sizeof...(Cs)];
  44.  
  45. // helper to get the i_th character (`\0` for out of bound)
  46. template <std::size_t I, std::size_t N>
  47. constexpr char at(const char (&a)[N]) { return I < N ? a[I] : '\0'; }
  48.  
  49. // helper to check if the c-string will not be truncated
  50. template <std::size_t max_size, std::size_t N>
  51. constexpr bool check_size(const char (&)[N])
  52. {
  53. static_assert(N <= max_size, "string too long");
  54. return N <= max_size;
  55. }
  56.  
  57. // Helper macros to build char_sequence from c-string
  58. #define PUSH_BACK_8(S, I) \
  59.   ::push_back<at<(I) + 0>(S)>::push_back<at<(I) + 1>(S)> \
  60.   ::push_back<at<(I) + 2>(S)>::push_back<at<(I) + 3>(S)> \
  61.   ::push_back<at<(I) + 4>(S)>::push_back<at<(I) + 5>(S)> \
  62.   ::push_back<at<(I) + 6>(S)>::push_back<at<(I) + 7>(S)>
  63.  
  64. #define PUSH_BACK_32(S, I) \
  65.   PUSH_BACK_8(S, (I) + 0) PUSH_BACK_8(S, (I) + 8) \
  66.   PUSH_BACK_8(S, (I) + 16) PUSH_BACK_8(S, (I) + 24)
  67.  
  68. #define PUSH_BACK_128(S, I) \
  69.   PUSH_BACK_32(S, (I) + 0) PUSH_BACK_32(S, (I) + 32) \
  70.   PUSH_BACK_32(S, (I) + 64) PUSH_BACK_32(S, (I) + 96)
  71.  
  72. // Macro to create char_sequence from c-string (limited to 128 chars)
  73. #define MAKE_CHAR_SEQUENCE(S) \
  74.   strip_sequence<char_sequence<> \
  75.   PUSH_BACK_128(S, 0) \
  76.   >::type::template push_back<check_size<128>(S) ? '\0' : '\0'>
  77.  
  78. // Macro to return an aligned c-string
  79. #define MAKE_ALIGNED_STRING(ALIGNMENT, S) \
  80.   aligned_string<ALIGNMENT, MAKE_CHAR_SEQUENCE(S)>::str
  81.  
  82. // Test it:
  83.  
  84. #include <iostream>
  85.  
  86. int main()
  87. {
  88. constexpr const char* strings[] = {
  89. MAKE_ALIGNED_STRING(16, ""),
  90. MAKE_ALIGNED_STRING(16, "1234567890123456789012345678901234567890"),
  91. MAKE_ALIGNED_STRING(16, "hello world"),
  92. MAKE_ALIGNED_STRING(16, "hello"),
  93. MAKE_ALIGNED_STRING(16, "world")
  94. };
  95. static_assert((std::uintptr_t(strings[0]) & 0x0F) == 0, "misaligned");
  96. static_assert((std::uintptr_t(strings[1]) & 0x0F) == 0, "misaligned");
  97. static_assert((std::uintptr_t(strings[2]) & 0x0F) == 0, "misaligned");
  98. static_assert((std::uintptr_t(strings[3]) & 0x0F) == 0, "misaligned");
  99. static_assert((std::uintptr_t(strings[4]) & 0x0F) == 0, "misaligned");
  100.  
  101. for (auto s : strings) {
  102. std::cout << s << " " << static_cast<const void*>(s) << std::endl;
  103. }
  104. return 0;
  105. }
  106.  
Success #stdin #stdout 0s 3296KB
stdin
Standard input is empty
stdout
 0x8048a90
1234567890123456789012345678901234567890 0x8048a60
hello world 0x8048a50
hello 0x8048a40
world 0x8048a30