fork download
  1. #include <iostream>
  2. #include <set>
  3. #include <stdexcept>
  4. #include <string>
  5. #include <functional>
  6.  
  7. template<typename T>
  8. struct identity
  9. {
  10. using type = T;
  11. };
  12.  
  13. template<char ... Ch>
  14. struct const_string : identity<const_string<Ch...>>
  15. {
  16. static char constexpr nt_arr[]{ Ch..., '\0' };
  17.  
  18. static std::size_t constexpr length = sizeof...(Ch);
  19.  
  20. private:
  21. constexpr std::size_t _count_impl( char c, std::size_t index )
  22. {
  23. return nt_arr[index] == c + (index == 0 ? 0 : _count_impl(c, index - 1));
  24. }
  25.  
  26. public:
  27. constexpr std::size_t count( char c )
  28. { return _count_impl( c, sizeof(nt_arr) - 1 ); }
  29. };
  30.  
  31. template<char ... Ch>
  32. char constexpr const_string<Ch...>::nt_arr[];
  33.  
  34. /// concat_strings //////////////////////////////////////////////////////////////////
  35.  
  36. template<typename, typename> struct concat_strings;
  37.  
  38. template<char ... first,
  39. char ... second>
  40. struct concat_strings<const_string<first...>, const_string<second...>> : const_string<first..., second...> {};
  41.  
  42. /// type_list ///////////////////////////////////////////////////////////////////////
  43.  
  44. // Geht natürlich auch ohne Rekursion, ist nunmal auf die Schnelle gemacht:
  45. template<std::size_t index, typename T, typename ... Types>
  46. struct at : at<index-1, Types...> {};
  47. template<typename T, typename ... Types>
  48. struct at<0, T, Types...> : identity<T> {};
  49.  
  50. template<typename ... Types>
  51. struct type_list : identity<type_list<Types...>>
  52. {
  53. static std::size_t constexpr length = sizeof...(Types);
  54.  
  55. template<std::size_t index>
  56. struct get : at<index, Types...> {};
  57. };
  58.  
  59. template<typename... Args>
  60. type_list<Args...> arg_type_list( Args&&... );
  61.  
  62. template<std::size_t i, typename T>
  63. struct indexed_type
  64. {
  65. static constexpr std::size_t index = i;
  66. using type = T;
  67. };
  68.  
  69. /// concat_type_lists //////////////////////////////////////////////////////////
  70.  
  71. template<typename, typename> struct concat_type_lists;
  72.  
  73. template<typename ... first,
  74. typename ... second>
  75. struct concat_type_lists<type_list<first...>, type_list<second...>> : type_list<first..., second...> {};
  76.  
  77. /// split ////////////////////////////////////////////////////////////////////////
  78.  
  79. template<char, typename, typename, typename> struct split_on;
  80.  
  81. template<char token,
  82. typename ... pairs>
  83. struct split_on< token, type_list<pairs...>, const_string<>, const_string<> > : type_list<pairs...> {};
  84.  
  85.  
  86. template<char token,
  87. char ... last,
  88. typename ... pairs>
  89. struct split_on< token, type_list<pairs...>, const_string<last...>, const_string<> > : type_list< pairs..., indexed_type<0, const_string<last...>> > {};
  90.  
  91. // Kein Token vorhanden:
  92. template<char token,
  93. char current,
  94. char ... last,
  95. char ... tail,
  96. typename ... pairs>
  97. struct split_on< token, type_list<pairs...>, const_string<last...>, const_string<current, tail...> > : split_on<token, type_list<pairs...>, const_string<last..., current>, const_string<tail...>> {};
  98.  
  99. template<char C>
  100. struct enable_if_digit
  101. {
  102. static_assert( C >= '0' && C <= '9', "Not a digit!" );
  103.  
  104. static constexpr char ch = C;
  105. static constexpr int number = C - '0';
  106. };
  107.  
  108. template<char token,
  109. char digit,
  110. char ... last,
  111. typename ... pairs>
  112. struct split_on< token, type_list<pairs...>, const_string<last...>, const_string<token, digit> > :
  113. type_list<pairs..., indexed_type<enable_if_digit<digit>::number, const_string<last...>>, indexed_type<0, const_string<>>> {};
  114.  
  115. template<char token,
  116. char digit,
  117. char ... last,
  118. char ... tail,
  119. typename ... pairs>
  120. struct split_on< token, type_list<pairs...>, const_string<last...>, const_string<token, digit, tail...> > :
  121. split_on<token, type_list< pairs..., indexed_type<enable_if_digit<digit>::number, const_string<last...>> >, const_string<>, const_string<tail...>> {};
  122.  
  123. template<char token,
  124. char ... last,
  125. char ... tail,
  126. typename ... pairs>
  127. struct split_on< token, type_list<pairs...>, const_string<last...>, const_string<token, token, tail...> > : split_on<token, type_list<pairs...>, const_string<last..., token, token>, const_string<tail...>> {};
  128.  
  129. template<char c, typename> struct split;
  130. template<char c, char... chars> struct split<c, const_string<chars...>> : split_on<c, type_list<>, const_string<>, const_string<chars...>> {};
  131.  
  132. /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  133.  
  134. template<char, typename> struct rtrim;
  135. template<char token, char first, char ... ch>
  136. struct rtrim<token, const_string<first, ch...>> : concat_strings<const_string<first>, typename rtrim<token, const_string<ch...>>::type> {};
  137. template<char token, char ... ch>
  138. struct rtrim<token, const_string<token, ch...>> : const_string<> {};
  139. template<char token>
  140. struct rtrim<token, const_string<>> : const_string<> {};
  141.  
  142. /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  143.  
  144. template<std::size_t Index, typename T>
  145. struct rack
  146. {
  147. static constexpr std::size_t index = Index;
  148.  
  149. T&& arg;
  150.  
  151. rack( T&& a ):
  152. arg( std::forward<T>(a) ) {}
  153. };
  154.  
  155. /// index-list (v. camper)
  156.  
  157. template<int ... args>
  158. struct index_list
  159. {
  160. static constexpr int arr[]{args...};
  161. using type = index_list;
  162. };
  163.  
  164. template <typename T, typename U> struct concat_list;
  165. template <int... i, int... j>
  166. struct concat_list<index_list<i...>,index_list<j...>>
  167. : index_list<i..., (sizeof...(i)+i)..., (2*sizeof...(i)+j)...> {};
  168.  
  169. template <int N> struct make_index_list
  170. : concat_list<typename make_index_list<N/2>::type, typename make_index_list<N%2>::type> {};
  171. template <> struct make_index_list<1> : index_list<0> {};
  172. template <> struct make_index_list<0> : index_list<> {};
  173.  
  174. /// </camper> /
  175.  
  176. template<typename, typename...> struct Indicer;
  177.  
  178. template<int... indices, typename... Args>
  179. struct Indicer<index_list<indices...>, Args...> : rack<indices, Args>...
  180. {
  181. Indicer( Args&&... args ):
  182. rack<indices, Args>(std::forward<Args>(args))... {}
  183. };
  184.  
  185. template<typename format_string,
  186. typename CharT,
  187. typename Traits,
  188. typename index_list>
  189. struct ts_printf_env;
  190.  
  191. template<typename format_string,
  192. typename CharT,
  193. typename Traits,
  194. int... indices>
  195. struct ts_printf_env<format_string, CharT, Traits, index_list<indices...>>
  196. {
  197. static char constexpr format_sign = '%';
  198.  
  199. using string_list = typename split<format_sign, format_string>::type;
  200.  
  201. private:
  202.  
  203. template<std::size_t type_list_index>
  204. static void ts_printf_impl( std::basic_ostream<CharT, Traits>& os )
  205. {
  206. using to_put = typename string_list::template get<type_list_index>::type::type;
  207.  
  208. if( os.rdbuf()->sputn( to_put::nt_arr, to_put::length ) != to_put::length )
  209. os.setstate( std::ios_base::badbit );
  210. }
  211.  
  212. template<std::size_t type_list_index,
  213. typename FirstArg,
  214. typename ...Args>
  215. static void ts_printf_impl( std::basic_ostream<CharT, Traits>& os,
  216. FirstArg&& first,
  217. Args&&... tail)
  218. {
  219. ts_printf_impl<type_list_index>( os );
  220.  
  221. if( os << std::forward<FirstArg>(first) )
  222. ts_printf_impl<type_list_index + 1>( os, std::forward<Args>(tail)... );
  223. }
  224.  
  225. public:
  226.  
  227. template<typename ... Args>
  228. static std::basic_ostream<CharT, Traits>& ts_printf( std::basic_ostream<CharT, Traits>& os, Args&&... args )
  229. {
  230. static_assert( sizeof...(Args) + 1 == string_list::length, "Invalid format string!" );
  231.  
  232. typename std::basic_ostream<CharT, Traits>::sentry ok{os};
  233.  
  234. if( ok ) try
  235. {
  236. Indicer<typename make_index_list<sizeof...(Args)>::type, Args...> indicer( std::forward<Args>(args)... );
  237.  
  238. #define index string_list::template get<indices>::type::index
  239. ts_printf_impl<0>( os, indicer.rack< index,
  240. typename at<index, Args...>::type >::arg... );
  241. #undef index
  242. }
  243. catch( std::ios::failure const& )
  244. { throw; }
  245. catch(...)
  246. {
  247. os.clear( os.rdstate() | std::ios_base::badbit );
  248. if( os.exceptions() & std::ios_base::badbit )
  249. throw;
  250. }
  251.  
  252. return os;
  253. }
  254. };
  255.  
  256. #define SPLIT_1(str,pos) str [ pos < sizeof str ? pos : sizeof(str) - 1 ]
  257. #define SPLIT_2(str,x) SPLIT_1(str,x), SPLIT_1(str,x + 1)
  258. #define SPLIT_4(str,x) SPLIT_2(str,x), SPLIT_2(str,x + 2)
  259. #define SPLIT_8(str,x) SPLIT_4(str,x), SPLIT_4(str,x + 4)
  260. #define SPLIT_16(str,x) SPLIT_8(str,x), SPLIT_8(str,x + 8)
  261. #define SPLIT_32(str,x) SPLIT_16(str,x), SPLIT_16(str,x + 16)
  262. #define SPLIT_64(str,x) SPLIT_32(str,x), SPLIT_32(str,x + 32)
  263. #define SPLIT_128(str,x) SPLIT_64(str,x), SPLIT_64(str,x + 64)
  264.  
  265. #define ts_printf(os, format, ...) ts_printf_env<typename rtrim<'\0', const_string<SPLIT_128(format, 0)>>::type, \
  266.   decltype(os)::char_type, \
  267.   decltype(os)::traits_type, \
  268.   make_index_list<decltype(arg_type_list(__VA_ARGS__))::length>::type>::ts_printf( os, __VA_ARGS__ )
  269.  
  270.  
  271. int main()
  272. {
  273. ts_printf(std::cout, "%1 + %2 = %0", 10, 6, 4);
  274. }
  275.  
Success #stdin #stdout 0s 2852KB
stdin
Standard input is empty
stdout
6 + 4 = 10