Traits.ih
Go to the documentation of this file.
1 //
2 // Copyright (c) 2020 Fraunhofer Institute for Applied Information Technology (FIT)
3 // Network Research Group (NET)
4 // Schloss Birlinghoven, 53754 Sankt Augustin, GERMANY
5 // Contact: support@wiback.org
6 //
7 // This file is part of the SENF code tree.
8 // It is licensed under the 3-clause BSD License (aka New BSD License).
9 // See LICENSE.txt in the top level directory for details or visit
10 // https://opensource.org/licenses/BSD-3-Clause
11 //
12 
13 
14 /** \file
15  \brief Traits internal header */
16 
17 #ifndef IH_SENF_Scheduler_Console_Traits_
18 #define IH_SENF_Scheduler_Console_Traits_ 1
19 
20 // Custom includes
21 #include <string>
22 #include <limits>
23 #include <boost/preprocessor/seq/for_each.hpp>
24 #include <boost/preprocessor/stringize.hpp>
25 #include <boost/preprocessor/facilities/empty.hpp>
26 #include <boost/preprocessor/if.hpp>
27 #include <boost/bimap.hpp>
28 #include <boost/assign/list_inserter.hpp>
29 #include <boost/algorithm/string/case_conv.hpp>
30 #include <boost/mpl/if.hpp>
31 #include <senf/Utils/preprocessor.hh>
32 
33 //-/////////////////////////////////////////////////////////////////////////////////////////////////
34 
35 namespace senf {
36 namespace console {
37 
38  template <class _> struct ArgumentTraits;
39  template <class _> struct ReturnValueTraits;
40 
41 namespace detail {
42 
43  template <class CharT>
44  struct MatchingShortType
45  : public boost::mpl::if_c<std::numeric_limits<CharT>::is_signed,short,unsigned short>
46  {};
47 
48  template <class CharT>
49  struct CharArgumentTraits
50  : public ArgumentTraits<typename MatchingShortType<CharT>::type>
51  {
52  typedef ArgumentTraits<typename MatchingShortType<CharT>::type> base;
53  typedef CharT type;
54  static void parse(ParseCommandInfo::TokensRange const & tokens, CharT & out);
55  static std::string description();
56  };
57 
58  template <class CharT>
59  struct CharReturnValueTraits
60  : public ReturnValueTraits<typename MatchingShortType<CharT>::type>
61  {
62  typedef CharT type;
63  };
64 
65  template <typename T>
66  struct EnumFormatter
67  {
68  T value;
69  EnumFormatter(T v) : value(v) {}
70  };
71  template <typename T>
72  inline std::ostream & operator<<(std::ostream & os, EnumFormatter<T> const & enumFormatter)
73  {
74  senf_console_format_value(enumFormatter.value, os);
75  return os;
76  }
77 
78 #ifndef DOXYGEN
79  struct StringILess
80  {
81  bool operator()(std::string const & left, std::string const & right) const
82  { return boost::algorithm::to_lower_copy(left)
83  < boost::algorithm::to_lower_copy(right); }
84  };
85 
86  typedef boost::bimap<boost::bimaps::set_of<std::string, StringILess>, long> EnumTable;
87 
88  long parseEnum(EnumTable const & table, ParseCommandInfo::TokensRange const & tokens);
89  std::string formatEnum(EnumTable const & table, long value);
90 
91 # define SENF_CONSOLE_REGISTER_ENUM_ELT(r,d,e) \
92  BOOST_PP_IF( SENF_CONSOLE_REGISTER_ENUM_HASKEY(e), \
93  SENF_CONSOLE_REGISTER_ENUM_WITHKEY, \
94  SENF_CONSOLE_REGISTER_ENUM_NOKEY )(d, e)
95 
96 # define SENF_CONSOLE_REGISTER_ENUM_GOBBLE__key(k,e)
97 # define SENF_CONSOLE_REGISTER_ENUM_GET_KEY__key(k,e) k
98 # define SENF_CONSOLE_REGISTER_ENUM_GET_ENUM__key(k,e) e
99 # define SENF_CONSOLE_REGISTER_ENUM_HASKEY(e) \
100  BOOST_PP_IS_EMPTY( SENF_CAT_RECURS1(SENF_CONSOLE_REGISTER_ENUM_GOBBLE__, e) )
101 
102 # define SENF_CONSOLE_REGISTER_ENUM_KEY_GETENUM(e) \
103  SENF_CAT_RECURS2(SENF_CONSOLE_REGISTER_ENUM_GET_ENUM__, e)
104 # define SENF_CONSOLE_REGISTER_ENUM_KEY_GETKEY(e) \
105  SENF_CAT_RECURS3(SENF_CONSOLE_REGISTER_ENUM_GET_KEY__, e)
106 
107 # define SENF_CONSOLE_REGISTER_ENUM_NOKEY(prefix, e) \
108  ( BOOST_PP_STRINGIZE(e), static_cast<long>(prefix e) )
109 
110 # define SENF_CONSOLE_REGISTER_ENUM_WITHKEY(prefix, e) \
111  ( SENF_CONSOLE_REGISTER_ENUM_KEY_GETKEY(e), \
112  static_cast<long>(prefix SENF_CONSOLE_REGISTER_ENUM_KEY_GETENUM(e)) )
113 
114 
115 # define SENF_CONSOLE_REGISTER_ENUM_(Prefix, Scope, Type, Values) \
116  inline senf::console::detail::EnumTable & senf_console_enum_table(Prefix Type) \
117  { \
118  static senf::console::detail::EnumTable table; \
119  if (table.empty()) \
120  boost::assign::insert(table) \
121  BOOST_PP_SEQ_FOR_EACH( \
122  SENF_CONSOLE_REGISTER_ENUM_ELT, Prefix Scope, Values ); \
123  return table; \
124  } \
125  inline void senf_console_parse_argument( \
126  senf::console::ParseCommandInfo::TokensRange const & tokens, Prefix Type & out) \
127  { \
128  out = static_cast<Prefix Type>( \
129  senf::console::detail::parseEnum( \
130  senf_console_enum_table( Prefix Type() ), tokens) ); \
131  } \
132  inline void senf_console_format_value(Prefix Type value, std::ostream & os) \
133  { \
134  os << senf::console::detail::formatEnum( \
135  senf_console_enum_table( Prefix Type() ), static_cast<long>(value) ); \
136  } \
137  inline senf::console::detail::EnumFormatter<Prefix Type> \
138  senf_console_format_enum(Prefix Type value) \
139  { \
140  return senf::console::detail::EnumFormatter<Prefix Type>(value); \
141  }
142 
143 
144 # define SENF_CONSOLE_PARSE_TUPLE_ELT(r, d, member) \
145  senf::console::parse( *(arg++), out.member );
146 
147 # define SENF_CONSOLE_FORMAT_TUPLE_ELT(r, d, i, member) \
148  os << BOOST_PP_IF(i, " ", "") \
149  << senf::console::str(value.member); \
150 
151 # define SENF_CONSOLE_PARSE_AS_TUPLE_(Type, Members) \
152  namespace senf { \
153  namespace console { \
154  template <> \
155  struct ArgumentTraits<Type> \
156  { \
157  typedef Type type; \
158  static bool const singleToken = false; \
159  static void parse(ParseCommandInfo::TokensRange const & tokens, Type & out) \
160  { \
161  senf::console::CheckedArgumentIteratorWrapper arg (tokens); \
162  BOOST_PP_SEQ_FOR_EACH( SENF_CONSOLE_PARSE_TUPLE_ELT, _, Members ); \
163  } \
164  static std::string description() \
165  { \
166  return prettyBaseName(typeid(Type)); \
167  } \
168  static std::string str(Type const & value) \
169  { \
170  std::stringstream ss; \
171  senf::console::format(value, ss); \
172  return ss.str(); \
173  } \
174  }; \
175  }}
176 
177 # define SENF_CONSOLE_FORMAT_AS_TUPLE_(Type, Members) \
178  namespace senf { \
179  namespace console { \
180  template <> \
181  struct ReturnValueTraits<Type> \
182  { \
183  typedef Type type; \
184  static void format(Type const & value, std::ostream & os) \
185  { \
186  os << '('; \
187  BOOST_PP_SEQ_FOR_EACH_I( SENF_CONSOLE_FORMAT_TUPLE_ELT, , Members ); \
188  os << ')'; \
189  } \
190  }; \
191  }}
192 
193 # define SENF_CONSOLE_PARSE_AS_MAP_ELT(r, d, i, KeyMemberTuple) \
194  if (key == BOOST_PP_TUPLE_ELEM(2, 0, KeyMemberTuple)) { \
195  senf::console::parse( *(arg++), out. BOOST_PP_TUPLE_ELEM(2, 1, KeyMemberTuple)); \
196  keyBitmap &= ~(1 << i); \
197  continue; \
198  }
199 
200 # define SENF_CONSOLE_PARSE_AS_MAP_ERROR_ELT(r, d, i, KeyMemberTuple) \
201  if (ffs(keyBitmap) == i+1) \
202  throw SyntaxErrorException("Key missing: ") \
203  << BOOST_PP_TUPLE_ELEM(2, 0, KeyMemberTuple);
204 
205 # define SENF_CONSOLE_FORMAT_AS_MAP_ELT(r, d, i, KeyMemberTuple) \
206  os << BOOST_PP_IF(i, " ", "") \
207  << senf::console::str(BOOST_PP_TUPLE_ELEM(2, 0, KeyMemberTuple)) << '=' \
208  << senf::console::str(value.BOOST_PP_TUPLE_ELEM(2, 1, KeyMemberTuple));
209 
210 # define SENF_CONSOLE_PARSE_AS_MAP_(Type, KeyMemberTuples) \
211  namespace senf { \
212  namespace console { \
213  template <> \
214  struct ArgumentTraits<Type> \
215  { \
216  typedef Type type; \
217  static bool const singleToken = false; \
218  static void parse(ParseCommandInfo::TokensRange const & tokens, Type & out) \
219  { \
220  int keyBitmap = (1 << BOOST_PP_SEQ_SIZE(KeyMemberTuples)) - 1; \
221  std::string key; \
222  CheckedArgumentIteratorWrapper arg (tokens); \
223  while (arg) { \
224  senf::console::parse( *(arg++), key ); \
225  ParseCommandInfo::TokensRange sep (*(arg++)); \
226  if (sep.size() != 1 || sep[0].type() != Token::OtherPunctuation \
227  || sep[0].value() != "=") \
228  throw SyntaxErrorException("'=' expected"); \
229  BOOST_PP_SEQ_FOR_EACH_I( \
230  SENF_CONSOLE_PARSE_AS_MAP_ELT, _, KeyMemberTuples ); \
231  throw SyntaxErrorException("Unknown Key: " + key); \
232  } \
233  if (keyBitmap != 0) { \
234  BOOST_PP_SEQ_FOR_EACH_I( \
235  SENF_CONSOLE_PARSE_AS_MAP_ERROR_ELT, _, KeyMemberTuples ); \
236  } \
237  } \
238  static std::string description() \
239  { \
240  return prettyBaseName(typeid(Type)); \
241  } \
242  static std::string str(Type const & value) \
243  { \
244  std::stringstream ss; \
245  senf::console::format(value, ss); \
246  return ss.str(); \
247  } \
248  }; \
249  }}
250 
251 # define SENF_CONSOLE_FORMAT_AS_MAP_(Type, KeyMemberTuples) \
252  namespace senf { \
253  namespace console { \
254  template <> \
255  struct ReturnValueTraits<Type> \
256  { \
257  typedef Type type; \
258  static void format(Type const & value, std::ostream & os) \
259  { \
260  os << '('; \
261  BOOST_PP_SEQ_FOR_EACH_I( \
262  SENF_CONSOLE_FORMAT_AS_MAP_ELT, _, KeyMemberTuples ); \
263  os << ')'; \
264  } \
265  }; \
266  }}
267 
268 #endif
269 
270 }}}
271 
272 //-/////////////////////////////////////////////////////////////////////////////////////////////////
273 #endif
274 
275 
276 // Local Variables:
277 // mode: c++
278 // fill-column: 100
279 // comment-column: 40
280 // c-file-style: "senf"
281 // indent-tabs-mode: nil
282 // ispell-local-dictionary: "american"
283 // compile-command: "scons -u test"
284 // End: