xref: /aosp_15_r20/external/deqp/framework/delibs/decpp/deCommandLine.hpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 #ifndef _DECOMMANDLINE_HPP
2 #define _DECOMMANDLINE_HPP
3 /*-------------------------------------------------------------------------
4  * drawElements C++ Base Library
5  * -----------------------------
6  *
7  * Copyright 2014 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Command line parser.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "deDefs.hpp"
27 
28 #include <map>
29 #include <string>
30 #include <vector>
31 #include <ostream>
32 #include <typeinfo>
33 #include <stdexcept>
34 
35 namespace de
36 {
37 namespace cmdline
38 {
39 
40 //! Default parsing function
41 template <typename ValueType>
42 void parseType(const char *src, ValueType *dst);
43 
44 template <typename T>
45 struct NamedValue
46 {
47     const char *name;
48     T value;
49 };
50 
51 template <typename OptName>
52 struct Option
53 {
54     typedef typename OptName::ValueType ValueType;
55     typedef void (*ParseFunc)(const char *src, ValueType *dst);
56 
57     // \note All assumed to point to static memory.
58     const char *shortName;
59     const char *longName;
60     const char *description;
61     const char *defaultValue; //!< Default value (parsed from string), or null if should not be set
62 
63     // \note Either parse or namedValues must be null.
64     ParseFunc parse;                             //!< Custom parsing function or null.
65     const NamedValue<ValueType> *namedValues;    //!< Named values or null.
66     const NamedValue<ValueType> *namedValuesEnd; //!< Named value list end.
67 
68     //! Construct generic option (string, int, boolean).
Optionde::cmdline::Option69     Option(const char *shortName_, const char *longName_, const char *description_, const char *defaultValue_ = DE_NULL)
70         : shortName(shortName_)
71         , longName(longName_)
72         , description(description_)
73         , defaultValue(defaultValue_)
74         , parse(parseType<ValueType>)
75         , namedValues(DE_NULL)
76         , namedValuesEnd(0)
77     {
78     }
79 
80     //! Option with custom parsing function.
Optionde::cmdline::Option81     Option(const char *shortName_, const char *longName_, const char *description_, ParseFunc parse_,
82            const char *defaultValue_ = DE_NULL)
83         : shortName(shortName_)
84         , longName(longName_)
85         , description(description_)
86         , defaultValue(defaultValue_)
87         , parse(parse_)
88         , namedValues(DE_NULL)
89         , namedValuesEnd(DE_NULL)
90     {
91     }
92 
93     //! Option that uses named values.
Optionde::cmdline::Option94     Option(const char *shortName_, const char *longName_, const char *description_,
95            const NamedValue<ValueType> *namedValues_, const NamedValue<ValueType> *namedValuesEnd_,
96            const char *defaultValue_ = DE_NULL)
97         : shortName(shortName_)
98         , longName(longName_)
99         , description(description_)
100         , defaultValue(defaultValue_)
101         , parse((ParseFunc)DE_NULL)
102         , namedValues(namedValues_)
103         , namedValuesEnd(namedValuesEnd_)
104     {
105     }
106 
107     //! Option that uses named values.
108     template <size_t NumNamedValues>
Optionde::cmdline::Option109     Option(const char *shortName_, const char *longName_, const char *description_,
110            const NamedValue<ValueType> (&namedValues_)[NumNamedValues], const char *defaultValue_ = DE_NULL)
111         : shortName(shortName_)
112         , longName(longName_)
113         , description(description_)
114         , defaultValue(defaultValue_)
115         , parse((ParseFunc)DE_NULL)
116         , namedValues(DE_ARRAY_BEGIN(namedValues_))
117         , namedValuesEnd(DE_ARRAY_END(namedValues_))
118     {
119     }
120 };
121 
122 template <class Option>
123 struct OptTraits
124 {
125     typedef typename Option::ValueType ValueType;
126 };
127 
128 //! Default value lookup
129 template <typename ValueType>
getTypeDefault(ValueType * dst)130 inline void getTypeDefault(ValueType *dst)
131 {
132     *dst = ValueType();
133 }
134 
135 template <>
136 void getTypeDefault<bool>(bool *dst);
137 
138 template <typename T>
isBoolean(void)139 inline bool isBoolean(void)
140 {
141     return false;
142 }
143 template <>
isBoolean(void)144 inline bool isBoolean<bool>(void)
145 {
146     return true;
147 }
148 
149 //! Is argument boolean-only value?
150 template <class Option>
isBooleanOpt(void)151 inline bool isBooleanOpt(void)
152 {
153     return isBoolean<typename OptTraits<Option>::ValueType>();
154 }
155 
156 namespace detail
157 {
158 
159 using std::map;
160 using std::string;
161 using std::vector;
162 
163 // TypedFieldMap implementation
164 
165 template <class Name>
166 struct TypedFieldTraits
167 {
168     // Generic implementation for cmdline.
169     typedef typename OptTraits<Name>::ValueType ValueType;
170 };
171 
172 template <class Value>
173 struct TypedFieldValueTraits
174 {
destroyde::cmdline::detail::TypedFieldValueTraits175     static void destroy(void *value)
176     {
177         delete (Value *)value;
178     }
179 };
180 
181 class TypedFieldMap
182 {
183 public:
184     TypedFieldMap(void);
185     ~TypedFieldMap(void);
186 
empty(void) const187     bool empty(void) const
188     {
189         return m_fields.empty();
190     }
191     void clear(void);
192 
193     template <typename Name>
194     void set(typename TypedFieldTraits<Name>::ValueType *value);
195 
196     template <typename Name>
197     void set(const typename TypedFieldTraits<Name>::ValueType &value);
198 
199     template <typename Name>
200     bool contains(void) const;
201 
202     template <typename Name>
203     const typename TypedFieldTraits<Name>::ValueType &get(void) const;
204 
205 private:
206     TypedFieldMap(const TypedFieldMap &);
207     TypedFieldMap &operator=(const TypedFieldMap &);
208 
209     typedef void (*DestroyFunc)(void *);
210 
211     struct Entry
212     {
213         void *value;
214         DestroyFunc destructor;
215 
Entryde::cmdline::detail::TypedFieldMap::Entry216         Entry(void) : value(DE_NULL), destructor(0)
217         {
218         }
Entryde::cmdline::detail::TypedFieldMap::Entry219         Entry(void *value_, DestroyFunc destructor_) : value(value_), destructor(destructor_)
220         {
221         }
222     };
223 
224     typedef std::map<const std::type_info *, Entry> Map;
225 
226     bool contains(const std::type_info *key) const;
227     const Entry &get(const std::type_info *key) const;
228     void set(const std::type_info *key, const Entry &value);
229 
230     Map m_fields;
231 };
232 
233 template <typename Name>
set(typename TypedFieldTraits<Name>::ValueType * value)234 inline void TypedFieldMap::set(typename TypedFieldTraits<Name>::ValueType *value)
235 {
236     set(&typeid(Name), Entry(value, &TypedFieldValueTraits<typename TypedFieldTraits<Name>::ValueType>::destroy));
237 }
238 
239 template <typename Name>
set(const typename TypedFieldTraits<Name>::ValueType & value)240 void TypedFieldMap::set(const typename TypedFieldTraits<Name>::ValueType &value)
241 {
242     typename TypedFieldTraits<Name>::ValueType *copy = new typename TypedFieldTraits<Name>::ValueType(value);
243 
244     try
245     {
246         set<Name>(copy);
247     }
248     catch (...)
249     {
250         delete copy;
251         throw;
252     }
253 }
254 
255 template <typename Name>
contains(void) const256 inline bool TypedFieldMap::contains(void) const
257 {
258     return contains(&typeid(Name));
259 }
260 
261 template <typename Name>
get(void) const262 inline const typename TypedFieldTraits<Name>::ValueType &TypedFieldMap::get(void) const
263 {
264     return *static_cast<typename TypedFieldTraits<Name>::ValueType *>(get(&typeid(Name)).value);
265 }
266 
267 class CommandLine;
268 
269 typedef void (*GenericParseFunc)(const char *src, void *dst);
270 
271 class Parser
272 {
273 public:
274     Parser(void);
275     ~Parser(void);
276 
277     template <class OptType>
278     void addOption(const Option<OptType> &option);
279 
280     bool parse(int numArgs, const char *const *args, CommandLine *dst, std::ostream &err) const;
281 
282     void help(std::ostream &dst) const;
283 
284 private:
285     Parser(const Parser &);
286     Parser &operator=(const Parser &);
287 
288     struct OptInfo;
289 
290     typedef void (*DispatchParseFunc)(const OptInfo *info, const char *src, TypedFieldMap *dst);
291     typedef void (*SetDefaultFunc)(TypedFieldMap *dst);
292 
293     struct OptInfo
294     {
295         const char *shortName;
296         const char *longName;
297         const char *description;
298         const char *defaultValue;
299         bool isFlag; //!< Set true for bool typed arguments that do not used named values.
300 
301         GenericParseFunc parse;
302 
303         const void *namedValues;
304         const void *namedValuesEnd;
305         size_t namedValueStride;
306 
307         DispatchParseFunc dispatchParse;
308         SetDefaultFunc setDefault;
309 
OptInfode::cmdline::detail::Parser::OptInfo310         OptInfo(void)
311             : shortName(DE_NULL)
312             , longName(DE_NULL)
313             , description(DE_NULL)
314             , defaultValue(DE_NULL)
315             , isFlag(false)
316             , parse(DE_NULL)
317             , namedValues(DE_NULL)
318             , namedValuesEnd(DE_NULL)
319             , namedValueStride(0)
320             , dispatchParse(DE_NULL)
321             , setDefault(DE_NULL)
322         {
323         }
324     };
325 
326     void addOption(const OptInfo &option);
327 
328     template <typename OptName>
329     static void dispatchParse(const OptInfo *info, const char *src, TypedFieldMap *dst);
330 
331     vector<OptInfo> m_options;
332 };
333 
334 template <class OptType>
operator <<(Parser & parser,const Option<OptType> & option)335 inline Parser &operator<<(Parser &parser, const Option<OptType> &option)
336 {
337     parser.addOption(option);
338     return parser;
339 }
340 
341 //! Find match by name. Throws exception if no match is found.
342 const void *findNamedValueMatch(const char *src, const void *namedValues, const void *namedValuesEnd, size_t stride);
343 
344 template <typename OptType>
dispatchParse(const OptInfo * info,const char * src,TypedFieldMap * dst)345 void Parser::dispatchParse(const OptInfo *info, const char *src, TypedFieldMap *dst)
346 {
347     typename OptTraits<OptType>::ValueType *value = new typename OptTraits<OptType>::ValueType();
348     try
349     {
350         DE_ASSERT((!!info->parse) != (!!info->namedValues));
351         if (info->parse)
352         {
353             ((typename Option<OptType>::ParseFunc)(info->parse))(src, value);
354         }
355         else
356         {
357             const void *match =
358                 findNamedValueMatch(src, info->namedValues, info->namedValuesEnd, info->namedValueStride);
359             *value = static_cast<const NamedValue<typename OptTraits<OptType>::ValueType> *>(match)->value;
360         }
361         dst->set<OptType>(value);
362     }
363     catch (...)
364     {
365         delete value;
366         throw;
367     }
368 }
369 
370 template <typename OptType>
dispatchSetDefault(TypedFieldMap * dst)371 void dispatchSetDefault(TypedFieldMap *dst)
372 {
373     typename OptTraits<OptType>::ValueType *value = new typename OptTraits<OptType>::ValueType();
374     try
375     {
376         getTypeDefault<typename OptTraits<OptType>::ValueType>(value);
377         dst->set<OptType>(value);
378     }
379     catch (...)
380     {
381         delete value;
382         throw;
383     }
384 }
385 
386 template <typename OptType>
getNamedValueName(const void * value)387 const char *getNamedValueName(const void *value)
388 {
389     const NamedValue<typename OptTraits<OptType>::ValueType> *typedVal =
390         static_cast<const NamedValue<typename OptTraits<OptType>::ValueType>>(value);
391     return typedVal->name;
392 }
393 
394 template <typename OptType>
setFromNamedValue(const void * value,TypedFieldMap * dst)395 void setFromNamedValue(const void *value, TypedFieldMap *dst)
396 {
397     const NamedValue<typename OptTraits<OptType>::ValueType> *typedVal =
398         static_cast<const NamedValue<typename OptTraits<OptType>::ValueType>>(value);
399     dst->set<OptType>(typedVal->value);
400 }
401 
402 template <class OptType>
addOption(const Option<OptType> & option)403 void Parser::addOption(const Option<OptType> &option)
404 {
405     OptInfo opt;
406 
407     opt.shortName        = option.shortName;
408     opt.longName         = option.longName;
409     opt.description      = option.description;
410     opt.defaultValue     = option.defaultValue;
411     opt.isFlag           = isBooleanOpt<OptType>() && !option.namedValues;
412     opt.parse            = (GenericParseFunc)option.parse;
413     opt.namedValues      = (const void *)option.namedValues;
414     opt.namedValuesEnd   = (const void *)option.namedValuesEnd;
415     opt.namedValueStride = sizeof(*option.namedValues);
416     opt.dispatchParse    = dispatchParse<OptType>;
417 
418     if (opt.isFlag)
419         opt.setDefault = dispatchSetDefault<OptType>;
420 
421     addOption(opt);
422 }
423 
424 class CommandLine
425 {
426 public:
CommandLine(void)427     CommandLine(void)
428     {
429     }
~CommandLine(void)430     ~CommandLine(void)
431     {
432     }
433 
434     void clear(void);
435 
getOptions(void) const436     const TypedFieldMap &getOptions(void) const
437     {
438         return m_options;
439     }
getArgs(void) const440     const vector<string> &getArgs(void) const
441     {
442         return m_args;
443     }
444 
445     template <typename Option>
hasOption(void) const446     bool hasOption(void) const
447     {
448         return m_options.contains<Option>();
449     }
450 
451     template <typename Option>
getOption(void) const452     const typename TypedFieldTraits<Option>::ValueType &getOption(void) const
453     {
454         return m_options.get<Option>();
455     }
456 
457     bool helpSpecified(void) const;
458 
459 private:
460     TypedFieldMap m_options;
461     vector<string> m_args;
462 
463     friend class Parser;
464 };
465 
466 } // namespace detail
467 
468 using detail::CommandLine;
469 using detail::Parser;
470 
471 void selfTest(void);
472 
473 } // namespace cmdline
474 } // namespace de
475 
476 #define DE_DECLARE_COMMAND_LINE_OPT(NAME, TYPE) \
477     struct NAME                                 \
478     {                                           \
479         typedef TYPE ValueType;                 \
480     }
481 
482 #endif // _DECOMMANDLINE_HPP
483