PageRenderTime 70ms CodeModel.GetById 12ms app.highlight 52ms RepoModel.GetById 1ms app.codeStats 1ms

/prelude/type_strings.hpp

http://github.com/Eelis/geordi
C++ Header | 501 lines | 362 code | 118 blank | 21 comment | 23 complexity | b3c715dd958614ce1dfadf08b90ff8f1 MD5 | raw file
  1// Todo: Automatic parentheses placement.
  2
  3#ifndef TYPE_STRINGS_HPP
  4#define TYPE_STRINGS_HPP
  5
  6#if __cplusplus >= 201103
  7#include "lvalue_rvalue.hpp"
  8#endif
  9
 10#include <list>
 11#include <map>
 12#include <string>
 13#include <vector>
 14#include <stack>
 15#include <queue>
 16#include <set>
 17#include <utility>
 18#include <deque>
 19#include <iostream>
 20#include <fstream>
 21#include <sstream>
 22#include <ios>
 23#include <cassert>
 24#include <memory>
 25#include <cstring>
 26
 27#if __cplusplus >= 201103
 28#include <unordered_map>
 29#include <unordered_set>
 30#include <tuple>
 31#include <array>
 32#include <type_traits>
 33#include "tlists.hpp"
 34#endif
 35
 36#if __cplusplus >= 201500
 37#include <experimental/type_traits>
 38#endif
 39
 40namespace type_strings_detail {
 41
 42using std::basic_ostream;
 43
 44template <typename I>
 45std::string commas_and (I b, I e)
 46{
 47  assert(b != e);
 48  if (e - b == 3) { std::string r = *b++; r += ", " + *b++; return r + ", and " + *b; }
 49  else if (e - b == 2) { I c = b; ++c; return *b + " and " + *c; }
 50  else if (e - b == 1) return *b;
 51  else { I c = b; ++c; return *b + ", " + commas_and(c, e); }
 52}
 53
 54// Type strings in ordinary C++ syntax
 55
 56template <typename T>
 57char const * helper()
 58{
 59  return __PRETTY_FUNCTION__ + sizeof(
 60    #ifdef __clang__
 61      "const char* type_strings_detail::helper() [T = "
 62    #else
 63      "const char* type_strings_detail::helper() [with T = "
 64    #endif
 65      ) - 1;
 66}
 67
 68template <typename T> std::string type() {
 69  char const * const p = helper<T>();
 70  return std::string(p, std::strlen(p) - sizeof(']'));
 71}
 72
 73#define TYPEDEF_TYPE(n) template <> inline std::string type<std::n> () { return #n; }
 74
 75TYPEDEF_TYPE(ios)
 76TYPEDEF_TYPE(fstream)
 77TYPEDEF_TYPE(ifstream)
 78TYPEDEF_TYPE(ofstream)
 79TYPEDEF_TYPE(ostringstream)
 80TYPEDEF_TYPE(istringstream)
 81TYPEDEF_TYPE(stringstream)
 82TYPEDEF_TYPE(streambuf)
 83TYPEDEF_TYPE(iostream)
 84TYPEDEF_TYPE(ostream)
 85TYPEDEF_TYPE(istream)
 86TYPEDEF_TYPE(string)
 87TYPEDEF_TYPE(wstring)
 88
 89#undef TYPEDEF_TYPE
 90
 91// Verbose type description strings
 92
 93template <typename> std::string type_desc (bool plural = false);
 94
 95#if __cplusplus >= 201103
 96namespace textual_type_descriptions
 97{
 98  inline std::string pl (std::string const & s, bool const b) { return s + (b ? "s" : ""); }
 99
100  template <typename T> std::string many () { return type_desc<T>(true); }
101
102  template <typename> struct type_desc_t;
103
104  template <typename T> std::string an ()
105  { return (type_desc_t<T>::vowel ? "an " : "a ") + type_desc<T>(); }
106
107  template <typename T> std::string an_or_many (bool const plural = false)
108  { if (plural) return many<T>(); else return an<T>(); }
109
110  inline std::string to_string(int i)
111  {
112    std::ostringstream s;
113    s << i;
114    return s.str();
115  }
116
117  template <typename T> std::string count (size_t const i)
118  { return to_string(i) + " " + type_desc<T>(i != 1); }
119
120  template <typename T> std::string an_or_count (size_t const i) { return i == 1 ? an<T>() : count<T>(i); }
121
122  struct Vowel { enum { vowel = true }; };
123  struct consonant { enum { vowel = false }; };
124
125  template <typename T> struct type_desc_t: consonant
126  { static std::string s (bool b) { return pl(type<T>(), b); } };
127
128  template <typename T> std::string returning (bool const plural)
129  { return "returning " + an_or_many<T>(plural); }
130
131  template <> inline std::string returning<void> (bool) { return "returning nothing"; }
132
133  // built-in types
134
135  #define DEF_BUILTIN_SPEC(type, str, vow) \
136    template <> struct type_desc_t<type> \
137    { static std::string s (bool plural) { return pl(str, plural); } enum { vowel = vow }; };
138
139  DEF_BUILTIN_SPEC(bool, "boolean", false)
140  DEF_BUILTIN_SPEC(char, "character", false)
141  DEF_BUILTIN_SPEC(signed char, "signed character", false)
142  DEF_BUILTIN_SPEC(unsigned char, "unsigned character", true)
143  DEF_BUILTIN_SPEC(wchar_t, "wide character", false)
144  DEF_BUILTIN_SPEC(int, "integer", true)
145  DEF_BUILTIN_SPEC(long int, "long integer", false)
146  DEF_BUILTIN_SPEC(unsigned int, "unsigned integer", true)
147  DEF_BUILTIN_SPEC(long unsigned int, "long unsigned integer", false)
148
149  #undef DEF_BUILTIN_SPEC
150
151  // stdlib typedefs
152
153  #define TYPEDEF_TYPE_DESC(n, pl, vow) \
154    template <> struct type_desc_t<std::n> \
155    { static std::string s (bool b) { return b ? #n pl : #n; } enum { vowel = vow }; };
156
157  TYPEDEF_TYPE_DESC(ios, "es", true)
158  TYPEDEF_TYPE_DESC(fstream, "s", false)
159  TYPEDEF_TYPE_DESC(ifstream, "s", true)
160  TYPEDEF_TYPE_DESC(ofstream, "s", true)
161  TYPEDEF_TYPE_DESC(ostringstream, "s", true)
162  TYPEDEF_TYPE_DESC(istringstream, "s", true)
163  TYPEDEF_TYPE_DESC(stringstream, "s", false)
164  TYPEDEF_TYPE_DESC(streambuf, "s", false)
165  TYPEDEF_TYPE_DESC(iostream, "s", true)
166  TYPEDEF_TYPE_DESC(ostream, "s", true)
167  TYPEDEF_TYPE_DESC(istream, "s", true)
168  TYPEDEF_TYPE_DESC(string, "s", false)
169  TYPEDEF_TYPE_DESC(wstring, "s", false)
170
171  #undef TYPEDEF_TYPE_DESC
172
173  // primitive constructs
174
175  template <> struct type_desc_t<void>
176  { static std::string s (bool) { return "void"; } }; // has no plural
177
178  template <typename T> struct type_desc_t<T const>: consonant
179  { static std::string s (bool b) { return "constant " + type_desc<T>(b); } };
180
181  template <typename T> struct type_desc_t<T volatile>: consonant
182  { static std::string s (bool b) { return "volatile " + type_desc<T>(b); } };
183
184  template <typename T> struct type_desc_t<T const volatile>: consonant
185  { static std::string s (bool b) { return "constant volatile " + type_desc<T>(b); } };
186
187  template <typename T> struct type_desc_t<T *>: consonant
188  { static std::string s (bool b) { return pl("pointer", b) + " to " + an_or_many<T>(b); } };
189
190  template <> struct type_desc_t<void *>: consonant
191  { static std::string s (bool b) { return pl("pointer", b) + " to anything"; } };
192
193  template <typename T> struct type_desc_t<T &>: Vowel
194  { static std::string s (bool b) { return pl("lvalue reference", b) + " to " + an_or_many<T>(b); } };
195
196  #if __cplusplus >= 201103
197  template <typename T> struct type_desc_t<T &&>: Vowel
198  { static std::string s (bool b) { return pl("rvalue reference", b) + " to " + an_or_many<T>(b); } };
199  #endif
200
201  #define TYPE_STRINGS_EMPTY
202
203  #define ARRAY_SPEC(cv) \
204    template <typename T> struct type_desc_t<T cv []>: Vowel \
205    { static std::string s (bool b) { return pl("array", b) + " of " + many<T cv>(); } };
206
207  ARRAY_SPEC(TYPE_STRINGS_EMPTY)
208  ARRAY_SPEC(const)
209  ARRAY_SPEC(volatile)
210  ARRAY_SPEC(const volatile)
211
212  #undef ARRAY_SPEC
213
214  #define ARRAY_SPEC(cv) \
215    template <typename T, size_t N> struct type_desc_t<T cv [N]>: Vowel \
216    { static std::string s (bool b) { return pl("array", b) + " of " + count<T cv>(N); } };
217
218  ARRAY_SPEC(TYPE_STRINGS_EMPTY)
219  ARRAY_SPEC(const)
220  ARRAY_SPEC(volatile)
221  ARRAY_SPEC(const volatile)
222
223  #undef ARRAY_SPEC
224
225  #undef TYPE_STRINGS_EMPTY
226
227  template <typename> struct group_list_desc;
228
229  template<size_t N, typename T, typename... U>
230  struct group_list_desc<tlists::tlist<tlists::group<N, T>, U...> > {
231    static void s (std::vector<std::string> & v) {
232      v.push_back(an_or_count<T>(N)); group_list_desc<tlists::tlist<U...> >::s(v);
233  } };
234
235  template <> struct group_list_desc<tlists::tlist<> > { static void s (std::vector<std::string> &) {} };
236
237  template <typename... T>
238  struct list_desc: group_list_desc<typename tlists::group_successive<T...>::type> {};
239
240  // functions
241
242  template <typename T> struct type_desc_t<T ()>: consonant
243  { static std::string s (bool b) { return pl("nullary function", b) + " " + returning<T>(b); } };
244
245  template <typename T> struct type_desc_t<T (...)>: consonant
246  { static std::string s (bool b) { return pl("variadic function", b) + " " + returning<T>(b); } };
247
248  template <typename T, typename... U> struct type_desc_t<T (U...)>: consonant {
249    static std::string s (bool b) {
250      std::vector<std::string> v; list_desc<U...>::s(v); v.push_back(returning<T>(b));
251      return pl("function", b) + " taking " + commas_and(v.begin(), v.end());
252  } };
253
254  template <typename T, typename... U> struct type_desc_t<T (U..., ...)>: consonant {
255    static std::string s (bool b) {
256      std::vector<std::string> v; list_desc<U...>::s(v); v.push_back(returning<T>(b));
257      return pl("variadic function", b) + " taking at least " + commas_and(v.begin(), v.end());
258  } };
259
260  template<typename T> std::string class_key()
261  { return std::is_union<T>::value ? "union" : "class";  }
262
263  // data members
264
265  template <typename T, typename U> struct type_desc_t<T U:: *>: consonant
266  { static std::string s (bool b) { return pl("pointer", b) + " to data " + pl("member", b) + " of " + class_key<U>() + " " + type<U>() + " of type " + type_desc<T>(); } };
267
268  // member function pointers
269
270  enum CV { cv_, cv_c, cv_v, cv_cv };
271
272  inline char const * to_string(CV const cv)
273  {
274    switch (cv) {
275      case cv_: return "";
276      case cv_c: return "constant ";
277      case cv_v: return "volatile ";
278      case cv_cv: return "constant volatile ";
279      default: abort();
280    }
281  }
282
283  template <typename T, typename U, CV cv> struct type_desc_t_mem0: consonant
284  { static std::string s (bool b) { return pl("pointer", b) + " to " + to_string(cv) + "nullary member " + pl("function", b) + " of " + class_key<U>() + " " + type<U>() + " " + returning<T>(b); } };
285
286  template <typename T, typename U>
287  struct type_desc_t<T (U:: *) ()>: type_desc_t_mem0<T, U, cv_> {};
288  template <typename T, typename U>
289  struct type_desc_t<T (U:: *) () const>: type_desc_t_mem0<T, U, cv_c> {};
290  template <typename T, typename U>
291  struct type_desc_t<T (U:: *) () volatile>: type_desc_t_mem0<T, U, cv_v> {};
292  template <typename T, typename U>
293  struct type_desc_t<T (U:: *) () const volatile>: type_desc_t_mem0<T, U, cv_cv> {};
294
295  template <typename T, typename U, CV cv> struct type_desc_t_mem_vari: consonant
296  { static std::string s (bool b) { return pl("pointer", b) + " to " + to_string(cv) + "variadic member " + pl("function", b) + " of " + class_key<U>() + " " + type<U>() + " " + returning<T>(b); } };
297
298  template <typename T, typename U>
299  struct type_desc_t<T (U:: *) (...)>: type_desc_t_mem_vari<T, U, cv_> {};
300  template <typename T, typename U>
301  struct type_desc_t<T (U:: *) (...) const>: type_desc_t_mem_vari<T, U, cv_c> {};
302  template <typename T, typename U>
303  struct type_desc_t<T (U:: *) (...) volatile>: type_desc_t_mem_vari<T, U, cv_v> {};
304  template <typename T, typename U>
305  struct type_desc_t<T (U:: *) (...) const volatile>: type_desc_t_mem_vari<T, U, cv_cv> {};
306
307  template <typename T, typename U, CV cv, typename... P>
308  struct type_desc_t_memN: consonant {
309    static std::string s (bool b) {
310      std::vector<std::string> v; list_desc<P...>::s(v); v.push_back(returning<T>(b));
311      return pl("pointer", b) + " to " + to_string(cv) + "member " + pl("function", b) + " of " + class_key<U>() + " " + type<U>() + " taking " + commas_and(v.begin(), v.end());
312    }
313  };
314
315  template <typename T, typename U, typename... P>
316  struct type_desc_t<T (U:: *) (P...)>: type_desc_t_memN<T, U, cv_, P...> {};
317  template <typename T, typename U, typename... P>
318  struct type_desc_t<T (U:: *) (P...) const>: type_desc_t_memN<T, U, cv_c, P...> {};
319  template <typename T, typename U, typename... P>
320  struct type_desc_t<T (U:: *) (P...) volatile>: type_desc_t_memN<T, U, cv_v, P...> {};
321  template <typename T, typename U, typename... P>
322  struct type_desc_t<T (U:: *) (P...) const volatile>: type_desc_t_memN<T, U, cv_cv, P...> {};
323
324  template <typename T, typename U, CV cv, typename... P>
325  struct type_desc_t_memN_vari: consonant {
326    static std::string s (bool b) {
327      std::vector<std::string> v; list_desc<P...>::s(v); v.push_back(returning<T>(b));
328      return pl("pointer", b) + " to " + to_string(cv) + "variadic member " + pl("function", b) + " of " + class_key<U>() + " " + type<U>() + " taking at least " + commas_and(v.begin(), v.end());
329    }
330  };
331
332  template <typename T, typename U, typename... P>
333  struct type_desc_t<T (U:: *) (P..., ...)>: type_desc_t_memN_vari<T, U, cv_, P...> {};
334  template <typename T, typename U, typename... P>
335  struct type_desc_t<T (U:: *) (P..., ...) const>: type_desc_t_memN_vari<T, U, cv_c, P...> {};
336  template <typename T, typename U, typename... P>
337  struct type_desc_t<T (U:: *) (P..., ...) volatile>: type_desc_t_memN_vari<T, U, cv_v, P...> {};
338  template <typename T, typename U, typename... P>
339  struct type_desc_t<T (U:: *) (P..., ...) const volatile>: type_desc_t_memN_vari<T, U, cv_cv, P...> {};
340
341  // Library components:
342
343    // C++03
344
345    template <typename T, typename A> struct type_desc_t<std::vector<T, A> >: consonant
346    { static std::string s (bool b) { return pl("vector", b) + " of " + many<T>(); } };
347
348    template <typename T, typename U> struct type_desc_t<std::pair<T, U> >: consonant
349    { static std::string s (bool b) { return pl("pair", b) + " of " + an_or_many<T>(b) + " and " + an_or_many<U>(b); } };
350
351    template <typename T> struct type_desc_t<std::pair<T, T> >: consonant
352    { static std::string s (bool b) { return pl("pair", b) + " of " + many<T>(); } };
353
354    template <typename T, typename A> struct type_desc_t<std::set<T, A> >: consonant
355    { static std::string s (bool b) { return pl("set", b) + " of " + many<T>(); } };
356
357    template <typename T> struct type_desc_t<std::multiset<T> >: consonant
358    { static std::string s (bool b) { return pl("multi-set", b) + " of " + many<T>(); } };
359
360      /* Like most containers, std::map has a couple of parameters with default arguments. We only want to return a nice verbose string for specializations which use the default arguments. Naively, we might expect that to get this effect, we should simply partially specialize for type_desc_t<map<T, U> >. However, that partial specialization will not match type_desc_t<map<int const, int> >, because this is really:
361
362        type_desc_t<map<int const, int, less<int const>, ...> > (note the double-const collapse),
363
364      while the partial specialization is really for:
365
366        type_desc_t<map<T, U, less<T const>, ...> >,
367
368      which doesn't match! This is why we use std::is_same below. As far as I can see map is the only container affected because it has this double-const collapse in its default arguments. */
369
370    template <typename T, typename U, typename V, typename W>
371    struct type_desc_t<std::map<T, U, V, W> >: consonant
372    { static std::string s (bool const b) {
373        if (std::is_same<std::map<T, U>, std::map<T, U, V, W> >::value)
374          return pl("map", b) + " from " + many<T>() + " to " + many<U>();
375        else return pl(type<std::map<T, U, V, W> >(), b);
376    } };
377
378    template <typename T, typename U> struct type_desc_t<std::multimap<T, U> >: consonant
379    { static std::string s (bool b) { return pl("multi-map", b) + " from " + many<T>() + " to " + many<U>(); } };
380
381    template <typename T> struct type_desc_t<std::list<T> >: consonant
382    { static std::string s (bool b) { return pl("list", b) + " of " + many<T>(); } };
383
384    template <typename T> struct type_desc_t<std::deque<T> >: consonant
385    { static std::string s (bool b) { return pl("double-ended queue", b) + " of " + many<T>(); } };
386
387    template <typename T> struct type_desc_t<std::queue<T> >: consonant
388    { static std::string s (bool b) { return pl("queue", b) + " of " + many<T>(); } };
389
390    template <typename T> struct type_desc_t<std::priority_queue<T> >: consonant
391    { static std::string s (bool b) { return pl("priority queue", b) + " of " + many<T>(); } };
392
393    template <typename T> struct type_desc_t<std::stack<T> >: consonant
394    { static std::string s (bool b) { return pl("stack", b) + " of " + many<T>(); } };
395
396    // C++0x
397
398    template <typename T> struct type_desc_t<std::shared_ptr<T> >: consonant
399    { static std::string s (bool b) { return "shared " + type_desc<T*>(b); } };
400
401    template <typename T, size_t N> struct type_desc_t<std::array<T, N> >: Vowel
402    { static std::string s (bool b) { return pl("array", b) + " of " + count<T>(N); } };
403
404    template<size_t N> struct num_vowel { enum { vowel = N == 8 || N == 18 }; };
405
406    template <typename... T> struct type_desc_t<std::tuple<T...>> {
407      static std::string s (bool b) {
408        std::vector<std::string> v; list_desc<T...>::s(v);
409        return std::to_string(sizeof...(T)) + "-" + pl("tuple", b) + " of " + commas_and(v.begin(), v.end());
410      }
411      enum { vowel = num_vowel<sizeof...(T)>::vowel };
412    };
413
414    #ifdef _UNIQUE_PTR_H
415    template <typename T> struct type_desc_t<std::unique_ptr<T>>: consonant
416    { static std::string s (bool b) { return "unique " + type_desc<T*>(b); } };
417    #endif
418
419    template <typename T> struct type_desc_t<std::reference_wrapper<T>>: consonant
420    { static std::string s (bool b) { return "reference wrapped " + type_desc_t<T>::s(b); } };
421
422    template <typename T, typename U, typename H, typename P, typename A> struct type_desc_t<std::unordered_map<T, U, H, P, A>>: consonant
423    { static std::string s (bool b) { return pl("unordered map", b) + " from " + many<T>() + " to " + many<U>(); } };
424
425    template <typename T, typename U, typename H, typename P, typename A> struct type_desc_t<std::unordered_multimap<T, U, H, P, A>>: consonant
426    { static std::string s (bool b) { return pl("unordered multi-map", b) + " from " + many<T>() + " to " + many<U>(); } };
427
428    template <typename T, typename H, typename P, typename A>
429    struct type_desc_t<std::unordered_set<T, H, P, A>>: consonant
430    { static std::string s (bool b) { return pl("unordered set", b) + " of " + many<T>(); } };
431
432    template <typename T, typename H, typename P, typename A> struct type_desc_t<std::unordered_multiset<T, H, P, A>>: consonant
433    { static std::string s (bool b) { return pl("unordered multi-set", b) + " of " + many<T>(); } };
434
435} // textual_type_descriptions
436#endif
437
438enum expr_cat { lvalue, xvalue, prvalue };
439
440inline char const * to_string(expr_cat c)
441{
442  switch (c)
443  {
444    case lvalue: return "lvalue";
445    case xvalue: return "xvalue";
446    case prvalue: return "prvalue";
447    default: return "?";
448  }
449}
450
451template <typename Ch, typename Tr>
452basic_ostream<Ch, Tr> & operator<<(basic_ostream<Ch, Tr> & o, expr_cat c)
453{
454  return o << to_string(c);
455}
456
457template<typename T>
458expr_cat expression_category()
459{
460  if (std::is_lvalue_reference<T>::value) return lvalue;
461  if (std::is_rvalue_reference<T>::value) return xvalue;
462  return prvalue;
463}
464
465template <typename T> std::string type_desc (bool const plural)
466{ return textual_type_descriptions::type_desc_t<T>::s(plural); }
467
468template <typename> struct type_desc_tag {};
469template <typename> struct type_tag {};
470template <typename> struct etype_tag {};
471template <typename> struct etype_desc_tag {};
472
473struct adl_hint {};
474
475template <typename Ch, typename Tr, typename T>
476basic_ostream<Ch, Tr> & operator<<(basic_ostream<Ch, Tr> & o, adl_hint(type_desc_tag<T>))
477{ return o << type_desc<T>(); }
478
479template <typename Ch, typename Tr, typename T>
480basic_ostream<Ch, Tr> & operator<<(basic_ostream<Ch, Tr> & o, adl_hint(type_tag<T>))
481{ return o << type<T>(); }
482
483template <typename Ch, typename Tr, typename T>
484basic_ostream<Ch, Tr> & operator<<(basic_ostream<Ch, Tr> & o, etype_tag<T>)
485{ return o << expression_category<T>() << ' ' << type<typename std::remove_reference<T>::type>(); }
486
487template <typename Ch, typename Tr, typename T>
488basic_ostream<Ch, Tr> & operator<<(basic_ostream<Ch, Tr> & o, etype_desc_tag<T>)
489{ return o << expression_category<T>() << ' ' << type_desc<typename std::remove_reference<T>::type>(); }
490
491} // type_strings_detail
492
493template <typename T> type_strings_detail::adl_hint
494  TYPE_DESC(type_strings_detail::type_desc_tag<T>) { return type_strings_detail::adl_hint(); }
495template <typename T> type_strings_detail::adl_hint
496  TYPE(type_strings_detail::type_tag<T>) { return type_strings_detail::adl_hint(); }
497
498#define TYPE(...) ::type_strings_detail::etype_tag<decltype(void(), (__VA_ARGS__))>{}
499#define TYPE_DESC(...) ::type_strings_detail::etype_desc_tag<decltype(void(), (__VA_ARGS__))>{}
500
501#endif // header guard