• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MikkelSchubert / adapterremoval / #36

22 Jul 2024 09:33AM UTC coverage: 87.26% (-12.7%) from 100.0%
#36

push

travis-ci

MikkelSchubert
remove duplicate tests

2185 of 2504 relevant lines covered (87.26%)

16293.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.57
/src/argparse.hpp
1
/*************************************************************************\
2
 * AdapterRemoval - cleaning next-generation sequencing reads            *
3
 *                                                                       *
4
 * Copyright (C) 2011 by Stinus Lindgreen - stinus@binf.ku.dk            *
5
 * Copyright (C) 2014 by Mikkel Schubert - mikkelsch@gmail.com           *
6
 *                                                                       *
7
 * This program is free software: you can redistribute it and/or modify  *
8
 * it under the terms of the GNU General Public License as published by  *
9
 * the Free Software Foundation, either version 3 of the License, or     *
10
 * (at your option) any later version.                                   *
11
 *                                                                       *
12
 * This program is distributed in the hope that it will be useful,       *
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15
 * GNU General Public License for more details.                          *
16
 *                                                                       *
17
 * You should have received a copy of the GNU General Public License     *
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. *
19
\*************************************************************************/
20
#pragma once
21

22
#include "commontypes.hpp" // for string_vec_citer, string_vec
23
#include <cstddef>         // for size_t
24
#include <functional>      // for less
25
#include <map>             // for map
26
#include <memory>          // for shared_ptr, unique_ptr
27
#include <string>          // for string
28
#include <vector>          // for vector
29

30
namespace adapterremoval {
31

32
namespace argparse {
33

34
class argument;
35

36
class sink;
37
class bool_sink;
38
class double_sink;
39
class uint_sink;
40
class str_sink;
41
class vec_sink;
42

43
using argument_ptr = std::shared_ptr<argument>;
44
using preprocess_ptr = void (*)(std::string&);
45

46
//! Parse results for command-line arguments
47
enum class parse_result
48
{
49
  //! Terminate now (e.g. --version or --help used)
50
  exit,
51
  //! Error occurred parsing arguments / invalid combination of args
52
  error,
53
  //! No errors parsing command-line arguments
54
  ok
55
};
56

57
/**
58
 * Simple type-safe parsing of command-line options.
59
 *
60
 * To handle a an argument, an object of type argument is assigned
61
 * to the argparse::parser using the [] operator. For example, the parse and
62
 * save an integer value to a variable when the user supplies the argument
63
 * '--example', the following is done:
64
 *
65
 * int target = 0; // Must be initialized!
66
 * argparse::parser argparser(...);
67
 * argparser
68
 *  .add_knob("--example", &target)
69
 *  .metavar("N")
70
 *  .help("the number of examples");
71
 * argparser.parse_args(argc, argv);
72
 *
73
 * Aliases can be created for command-line arguments simply by assigning the
74
 * same parser to multiple keys; for example, to alias '--example' as '-e':
75
 *
76
 * argparser["-e"] = argparser["--example"];
77
 *
78
 * The class automatically handles the following arguments:
79
 *  --help, --h, -help, -h: Displays the program help
80
 *  --version, -v: Displays the program name and version string
81
 *
82
 * In both cases, the parse_args function returns false.
83
 *
84
 * The assigned consumer_ptrs are owned by and freed by the argparse::parser
85
 * upon destruction of the object. Pointers assigned multiple times (i.e. when
86
 * used with aliases) are only freed once.
87
 */
88
class parser
89
{
90
public:
91
  parser();
92
  ~parser() = default;
174✔
93

94
  /** Sets the name used in --help and --version messages */
95
  void set_name(const std::string& name);
96
  /** Sets the version string used in --help and --version messages */
97
  void set_version(const std::string& version);
98
  /** Sets the preamble text used in --help */
99
  void set_preamble(const std::string& text);
100
  /** Sets the license text used in --licenses */
101
  void set_licenses(const std::string& text);
102

103
  /** Parses a set of command-line options as passed to main(argc, argv). */
104
  parse_result parse_args(const string_vec& args);
105

106
  /** Returns true if the option with the given key has been set. */
107
  bool is_set(const std::string& key) const;
108
  /** Returns the value associated with the argument as a string. */
109
  std::string value(const std::string& key) const;
110

111
  /** Add argument with metavar. By default this takes no values. */
112
  argument& add(const std::string& name, const std::string& metavar = "");
113

114
  /** Add a blank line between the previous and the next command. */
115
  void add_separator();
116

117
  /** Add a blank line and a header between the previous and next command. */
118
  void add_header(const std::string& header);
119

120
  /** Helper function; prints the program name and version string. */
121
  void print_version() const;
122
  /** Helper functions; prints the full set of help-text. */
123
  void print_help() const;
124
  /** Helper functions; formats and prints the licenses. */
125
  void print_licenses() const;
126

127
  /** Set the maximum terminal width. */
128
  void set_terminal_width(unsigned w);
129

130
  parser(const parser&) = delete;
131
  parser(parser&&) = delete;
132
  parser& operator=(const parser&) = delete;
133
  parser& operator=(parser&&) = delete;
134

135
private:
136
  void update_argument_map();
137

138
  argument_ptr find_argument(const std::string& key);
139

140
  struct argument_entry
848✔
141
  {
142
    std::string header{};
143
    argument_ptr argument{};
144
  };
145

146
  std::vector<argument_entry> m_args{};
147
  std::map<std::string, argument_ptr, std::less<>> m_keys{};
148

149
  //! Name of the program
150
  std::string m_name{};
151
  //! Version string for the program (excluding the name)
152
  std::string m_version{};
153
  //! Preamble text for the program.
154
  std::string m_preamble{};
155
  //! Licenses for the program.
156
  std::string m_licenses{};
157
  //! Maximum terminal width used for printing help messages
158
  unsigned m_terminal_width = 100;
159
};
160

161
/**
162
 * Base class for arguments;
163
 *
164
 * Each consumer must implement the consume function, which takes iterators to
165
 * the arguments following the key for this parser (i.e. not including the
166
 * --option). These then consume zero or more values, returning the number
167
 * thus consumed, or (size_t)-1 if the values were missing or invalid.
168
 */
169
class argument
170
{
171
public:
172
  struct argument_key
173
  {
174
    std::string name;
175
    bool deprecated;
176
  };
177

178
  explicit argument(const std::string& key, std::string metavar = "");
179
  ~argument() = default;
864✔
180

181
  /** Returns true if the consumer has consumed a value. */
182
  bool is_set() const { return m_times_set; }
105✔
183

184
  /** Returns true if the argument is deprecated. */
185
  bool is_deprecated() const { return m_deprecated; }
4✔
186

187
  /** Returns true if the argument is hidden. */
188
  bool is_hidden() const { return m_hidden; }
96✔
189

190
  /** Returns the canonical argument key. */
191
  const std::string& key() const { return m_key_long; }
66✔
192

193
  /** Returns the short argument key; may be an empty string. */
194
  const std::string& short_key() const { return m_key_short; }
70✔
195

196
  /** Returns long, short, and deprecated argument keys. */
197
  string_vec keys() const;
198
  /** Returns true if this key is a deprecated alias for this argument. */
199
  bool is_deprecated_alias(const std::string& key) const;
200

201
  /** Returns the meta-variable. May be an empty string. */
202
  const std::string& metavar() const { return m_metavar; }
12✔
203

204
  /** Returns help string with %default replaced with the default (if any). */
205
  std::string help() const;
206

207
  /** Indicates the minimum number of values taken by this argument */
208
  size_t min_values() const;
209
  /** Indicates the maximum number of values taken by this argument */
210
  size_t max_values() const;
211

212
  /** Options that MUST be specified along with this argument. */
213
  const string_vec& depends_on() const { return m_depends_on; }
104✔
214

215
  /** Options that must NOT be specified along with this argument. */
216
  const string_vec& conflicts_with() const { return m_conflicts_with; }
104✔
217

218
  /** Returns the value associated with the argument as a string. */
219
  std::string value() const;
220
  /** Returns the default value associated as a string. */
221
  std::string default_value() const;
222

223
  /** Set the metavar for this argument. */
224
  argument& metavar(const std::string& metavar);
225
  /** Set help string for this argument. */
226
  argument& help(const std::string& text);
227
  /** Create a short form of the argument. */
228
  argument& abbreviation(char key);
229
  /** Create deprecated alias for the argument. */
230
  argument& deprecated_alias(const std::string& key);
231
  /** The argument is deprecated. Implies `hidden()` */
232
  argument& deprecated();
233
  /** The argument will not be printed by -h/--help */
234
  argument& hidden();
235

236
  /** Option `key` MUST be specified along with this argument. */
237
  argument& depends_on(const std::string& key);
238
  /** Option `key` must NOT be specified along with this argument. */
239
  argument& conflicts_with(const std::string& key);
240

241
  bool_sink& bind_bool(bool* ptr);
242
  uint_sink& bind_uint(unsigned* ptr);
243
  double_sink& bind_double(double* ptr);
244
  str_sink& bind_str(std::string* ptr);
245
  vec_sink& bind_vec(string_vec* ptr);
246

247
  /** Parse the next arguments, returning the number of items parsed or -1. */
248
  size_t parse(string_vec_citer start, const string_vec_citer& end);
249

250
  argument(const argument&) = delete;
251
  argument(argument&&) = delete;
252
  argument& operator=(const argument&) = delete;
253
  argument& operator=(argument&&) = delete;
254

255
private:
256
  //! Number of times the argument has been specified
257
  unsigned m_times_set{};
258
  //! Default sink value
259
  bool m_default_sink{};
260
  //! Indicates if the argument is deprecated
261
  bool m_deprecated{};
262
  //! Deprecated keys (long and short) for this argument
263
  string_vec m_deprecated_keys{};
264
  //! Indicates if the argument is hidden
265
  bool m_hidden{};
266

267
  //! The long, canonical argument key
268
  std::string m_key_long{};
269
  //! An optional, short argument key
270
  std::string m_key_short{};
271

272
  //! Optional metavar (defaults to uppercase `m_name` without dashes)
273
  std::string m_metavar{};
274
  //! Help string; the string '%default' will be replaced with the current value
275
  std::string m_help{};
276

277
  //! This argument must be specified along with these arguments.
278
  string_vec m_depends_on{};
279
  //! This argument cannot be specified along with these arguments.
280
  string_vec m_conflicts_with{};
281

282
  std::unique_ptr<sink> m_sink{};
283
};
284

285
class sink
286
{
287
public:
288
  /** Creates a sink that takes exactly `n_values` values */
289
  explicit sink(size_t n_values);
290
  /** Creates a sink that takes between min and max values (incl.) */
291
  sink(size_t min_values, size_t max_values);
292

293
  virtual ~sink() = default;
223✔
294

295
  /** Returns the current argument value as a string. **/
296
  virtual std::string value() const = 0;
297
  /** Returns string-representation of the default value */
298
  virtual std::string default_value() const;
299

300
  /** Indicates if the sink has been supplied with a default value. */
301
  virtual bool has_default() const { return m_has_default; }
62✔
302

303
  /** See argument::consume */
304
  virtual size_t consume(string_vec_citer start,
305
                         const string_vec_citer& end) = 0;
306

307
  /** Returns the list of valid choices, if any, formatted as strings */
308
  virtual string_vec choices() const { return {}; };
48✔
309

310
  /** Indicates the minimum number of values taken by this sink */
311
  size_t min_values() const { return m_min_values; };
133✔
312

313
  /** Indicates the maximum number of values taken by this sink */
314
  size_t max_values() const { return m_max_values; };
131✔
315

316
  /** Sets pre-processor function used before validating input  */
317
  sink& with_preprocessor(preprocess_ptr func)
318
  {
319
    m_preprocess = func;
320
    return *this;
321
  }
322

323
  sink(const sink&) = delete;
324
  sink(sink&&) = delete;
325
  sink& operator=(const sink&) = delete;
326
  sink& operator=(sink&&) = delete;
327

328
protected:
329
  void set_has_default() { m_has_default = true; }
12✔
330

331
  void set_min_values(size_t n) { m_min_values = n; }
5✔
332

333
  void set_max_values(size_t n) { m_max_values = n; }
3✔
334

335
  /** Preprocess the value if a preprocessor was set */
336
  std::string preprocess(std::string value) const;
337

338
private:
339
  //! Indicates if the sink has been supplied with a default value
340
  bool m_has_default{};
341
  //! The minimum number of values taken by this sink
342
  size_t m_min_values{};
343
  //! The maximum number of values taken by this sink
344
  size_t m_max_values{};
345
  //! Function used to pre-process the user supplied arguments
346
  preprocess_ptr m_preprocess = nullptr;
347
};
348

349
class bool_sink : public sink
350
{
351
public:
352
  explicit bool_sink(bool* ptr);
353
  ~bool_sink() override = default;
300✔
354

290✔
355
  std::string value() const override;
×
356
  size_t consume(string_vec_citer start, const string_vec_citer& end) override;
357

358
  bool_sink(const bool_sink&) = delete;
359
  bool_sink(bool_sink&&) = delete;
360
  bool_sink& operator=(const bool_sink&) = delete;
361
  bool_sink& operator=(bool_sink&&) = delete;
362

363
private:
364
  bool* m_sink;
365
};
366

367
class uint_sink : public sink
368
{
369
public:
370
  explicit uint_sink(unsigned* ptr);
371
  ~uint_sink() override = default;
372

373
  uint_sink& with_default(unsigned value);
44✔
374
  std::string default_value() const override;
20✔
375

×
376
  std::string value() const override;
377
  size_t consume(string_vec_citer start, const string_vec_citer& end) override;
378

379
  uint_sink(const uint_sink&) = delete;
380
  uint_sink(uint_sink&&) = delete;
381
  uint_sink& operator=(const uint_sink&) = delete;
382
  uint_sink& operator=(uint_sink&&) = delete;
383

384
private:
385
  unsigned* m_sink = nullptr;
386
  //! Default value used for -h/--help output
387
  unsigned m_default{};
388
};
389

390
class double_sink : public sink
391
{
392
public:
393
  explicit double_sink(double* ptr);
394
  ~double_sink() override = default;
395

396
  double_sink& with_default(double value);
397
  std::string default_value() const override;
398

22✔
399
  std::string value() const override;
4✔
400
  size_t consume(string_vec_citer start, const string_vec_citer& end) override;
×
401

402
  double_sink(const double_sink&) = delete;
403
  double_sink(double_sink&&) = delete;
404
  double_sink& operator=(const double_sink&) = delete;
405
  double_sink& operator=(double_sink&&) = delete;
406

407
private:
408
  double* m_sink = nullptr;
409
  //! Default value used for -h/--help output
410
  double m_default{};
411
};
412

413
class str_sink : public sink
414
{
415
public:
416
  explicit str_sink(std::string* ptr);
417
  ~str_sink() override = default;
418

419
  str_sink& with_default(const char* value);
420
  str_sink& with_default(const std::string& value);
421
  str_sink& with_choices(const string_vec& choices);
422
  std::string default_value() const override;
423

89✔
424
  std::string value() const override;
5✔
425

84✔
426
  string_vec choices() const override { return m_choices; }
427

428
  size_t consume(string_vec_citer start, const string_vec_citer& end) override;
429

430
  str_sink(const str_sink&) = delete;
431
  str_sink(str_sink&&) = delete;
432
  str_sink& operator=(const str_sink&) = delete;
433
  str_sink& operator=(str_sink&&) = delete;
434

4✔
435
private:
436
  std::string* m_sink = nullptr;
437
  string_vec m_choices{};
438
  //! Default value used for -h/--help output
439
  std::string m_default{};
440
  //! Sink variable used if no sink was supplied
441
  std::string m_fallback_sink{};
442
};
443

444
class vec_sink : public sink
445
{
446
public:
447
  explicit vec_sink(string_vec* ptr);
448
  ~vec_sink() override = default;
449

450
  /** The minimum number of values expected on the command-line (default 1) */
451
  vec_sink& with_min_values(size_t n);
452
  /** The maximum number of values expected on the command-line (default inf) */
453
  vec_sink& with_max_values(size_t n);
454

455
  std::string value() const override;
456
  size_t consume(string_vec_citer start, const string_vec_citer& end) override;
30✔
457

10✔
458
  vec_sink(const vec_sink&) = delete;
×
459
  vec_sink(vec_sink&&) = delete;
460
  vec_sink& operator=(const vec_sink&) = delete;
461
  vec_sink& operator=(vec_sink&&) = delete;
462

463
private:
464
  string_vec* m_sink = nullptr;
465
};
466

467
} // namespace argparse
468

469
} // namespace adapterremoval
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc