Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e7b99c1

Browse files
committedJan 6, 2015
Release v2.0
Merge branch 'release-2.0'
2 parents ff85128 + 20c7f39 commit e7b99c1

File tree

17 files changed

+613
-32
lines changed

17 files changed

+613
-32
lines changed
 

‎examples/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ EX = command_line/command_line \
2525
container/maputil \
2626
container/tokenizer \
2727
debug/stl_print \
28+
io/abort \
2829
io/column \
2930
io/filterstream \
3031
io/indent \
3132
io/line_comment \
3233
io/multistream \
34+
io/prefix \
3335
io/redact \
3436
io/redirectstream \
3537
io/shunt \
@@ -41,6 +43,7 @@ EX = command_line/command_line \
4143
meta/indices \
4244
patterns/singleton \
4345
serialize/hex \
46+
serialize/line \
4447
serialize/text \
4548
signal/debug_handler \
4649
system/terminal

‎examples/command_line/command_line.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ auto& i = ValueArg<int, RangeReader<int, Range<int, 1, 10>>>::create("i")
3131
.alternate("int")
3232
.usage("<int>")
3333
.description("i | 1 <= i <= 10")
34-
.default_val(5);
34+
.required();
3535

3636
auto& h = ValueArg<uint64_t, HexReader<uint64_t>, HexWriter<uint64_t>>::create("j")
3737
.alternate("hex")

‎examples/io/abort.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2014 eric schkufza
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <iostream>
16+
#include <string>
17+
18+
#include "include/io/filterstream.h"
19+
#include "include/io/abort.h"
20+
21+
using namespace cpputil;
22+
using namespace std;
23+
24+
int main() {
25+
ofilterstream<Abort> os(cout);
26+
os.filter().code(1);
27+
28+
os << "You should see this..." << endl << "... but not this" << endl;
29+
30+
return 0;
31+
}

‎examples/io/prefix.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2014 eric schkufza
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <iostream>
16+
#include <string>
17+
18+
#include "include/io/filterstream.h"
19+
#include "include/io/prefix.h"
20+
21+
using namespace cpputil;
22+
using namespace std;
23+
24+
int main() {
25+
ofilterstream<Prefix> os(cout);
26+
os.filter().prefix("Hello world: ");
27+
28+
os << "This is" << endl << "a " << endl << "multi-line message" << endl;
29+
30+
return 0;
31+
}

‎examples/serialize/line.cc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2014 eric schkufza
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <iostream>
16+
#include <sstream>
17+
#include <string>
18+
19+
#include "include/serialize/line_reader.h"
20+
21+
using namespace cpputil;
22+
using namespace std;
23+
24+
int main() {
25+
stringstream ss;
26+
ss << "Line 1: You should see this." << endl;
27+
ss << "Line 2: You shouldn't see this." << endl;
28+
29+
string s;
30+
LineReader<> lr;
31+
lr(ss, s);
32+
33+
cout << s << endl;
34+
35+
return 0;
36+
}

‎include/bits/bit_manip.h

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@
1616
#define CPPUTIL_INCLUDE_BITS_BIT_MANIP_H
1717

1818
#include <cassert>
19-
#include <stdint.h>
20-
2119
#include <immintrin.h>
20+
#include <stdint.h>
2221

2322
namespace cpputil {
2423

@@ -30,19 +29,34 @@ class BitManip<uint64_t> {
3029
public:
3130
static size_t ntz(uint64_t x) {
3231
#ifdef __BMI__
33-
return _tzcnt_u64(x);
32+
return __builtin_ctzll(x);
3433
#else
35-
assert(false);
36-
return 0;
34+
// See https://graphics.stanford.edu/~seander/bithacks.html
35+
uint64_t res = 64;
36+
x &= -((int64_t)x);
37+
if (x) res--;
38+
if (x & 0x00000000ffffffff) res -= 32;
39+
if (x & 0x0000ffff0000ffff) res -= 16;
40+
if (x & 0x00ff00ff00ff00ff) res -= 8;
41+
if (x & 0x0f0f0f0f0f0f0f0f) res -= 4;
42+
if (x & 0x3333333333333333) res -= 2;
43+
if (x & 0x5555555555555555) res -= 1;
44+
return res;
3745
#endif
3846
}
3947

4048
static size_t pop_count(uint64_t x) {
4149
#ifdef __POPCNT__
42-
return _popcnt64(x);
50+
return __builtin_popcountll(x);
4351
#else
44-
assert(false);
45-
return 0;
52+
// See https://graphics.stanford.edu/~seander/bithacks.html
53+
uint64_t res = x - ((x >> 1) & 0x5555555555555555);
54+
res = ((res >> 2) & 0x3333333333333333) + (res & 0x3333333333333333);
55+
res = ((res >> 4) + res) & 0x0f0f0f0f0f0f0f0f;
56+
res = ((res >> 8) + res) & 0x00ff00ff00ff00ff;
57+
res = ((res >> 16) + res) & 0x0000ffff0000ffff;
58+
res = ((res >> 32) + res) & 0x00000000ffffffff;
59+
return res;
4660
#endif
4761
}
4862

‎include/command_line/arg.h

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,21 @@ class Arg {
8686
os << error_;
8787
}
8888

89+
/** Is this argument required? */
90+
bool is_required() const {
91+
return required_;
92+
}
93+
94+
/** Has this argument been set (or does it have a default value)? */
95+
bool has_been_provided() const {
96+
return is_provided_;
97+
}
98+
99+
/** Does this argument have a default? */
100+
bool has_default() const {
101+
return has_default_;
102+
}
103+
89104
/** Prints the value of an arg */
90105
virtual void debug(std::ostream& os) const = 0;
91106

@@ -100,11 +115,12 @@ class Arg {
100115
};
101116

102117
/** An arg must be assigned at least one alias */
103-
Arg(const std::string& opt) {
118+
Arg(const std::string& opt) : is_provided_(false), has_default_(false) {
104119
alternate(opt);
105120
usage("");
106121
description("(no description provided)");
107122
error("");
123+
required(false);
108124

109125
auto& ar = Singleton<ArgRegistry>::get();
110126
ar.insert(this);
@@ -166,6 +182,21 @@ class Arg {
166182
error_ = error;
167183
}
168184

185+
/** Reset the required argument. */
186+
void required(const bool val = true) {
187+
required_ = val;
188+
}
189+
190+
/** Reset whether this argument has a default. */
191+
void set_has_default(const bool val = true) {
192+
has_default_ = val;
193+
}
194+
195+
/** Indicate that this argument has been set now. */
196+
void set_provided() {
197+
is_provided_ = true;
198+
}
199+
169200
private:
170201
/** Aliases for this arg ,ie: "-h --help" */
171202
std::set<std::string> opts_;
@@ -178,6 +209,12 @@ class Arg {
178209
std::string description_;
179210
/** A non-empty value here indicates that a survivable error occurred */
180211
std::string error_;
212+
/** Is this argument mandatory? */
213+
bool required_;
214+
/** Has this argument been provided in some way? */
215+
bool is_provided_;
216+
/** Does this argument have a default? */
217+
bool has_default_;
181218
};
182219

183220
} // namespace cpputil

‎include/command_line/command_line.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "include/command_line/command_line_config.h"
2121
#include "include/command_line/file_arg.h"
2222
#include "include/command_line/flag_arg.h"
23+
#include "include/command_line/folder_arg.h"
2324
#include "include/command_line/heading.h"
2425
#include "include/command_line/value_arg.h"
2526

‎include/command_line/command_line_config.h

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ namespace cpputil {
3232
class CommandLineConfig {
3333
public:
3434
/** Strict parse with help, config, and debug support */
35-
static void strict_with_convenience(int argc, char** argv) {
35+
static void strict_with_convenience(int argc, char** argv, bool sort_args = false, bool show_defaults_in_Help = true) {
3636
Heading::create("Help and argument utilities:");
3737
auto& help = FlagArg::create("h")
3838
.alternate("help")
@@ -41,23 +41,23 @@ class CommandLineConfig {
4141
.description("Print program arguments and quit");
4242
auto& read_config = ValueArg<std::string>::create("config")
4343
.usage("<path/to/file.conf>")
44-
.default_val("")
4544
.description("Read program args from a configuration file");
4645
auto& write_config = ValueArg<std::string>::create("example_config")
4746
.usage("<path/to/file.conf>")
48-
.default_val("")
4947
.description("Print an example configuration file");
5048

51-
Args::sort_args([](Arg * a1, Arg * a2) {
52-
return *(a1->alias_begin()) < *(a2->alias_begin());
53-
});
49+
if (sort_args) {
50+
Args::sort_args([](Arg * a1, Arg * a2) {
51+
return *(a1->alias_begin()) < *(a2->alias_begin());
52+
});
53+
}
5454
Args::read(argc, argv);
5555

5656
if (help) {
5757
std::cout << std::endl;
5858
std::cout << "Usage: " << argv[0] << " [options]" << std::endl;
5959
std::cout << std::endl;
60-
write_help(std::cout);
60+
write_help(std::cout, show_defaults_in_Help);
6161
exit(0);
6262
}
6363

@@ -96,6 +96,23 @@ class CommandLineConfig {
9696
exit(1);
9797
}
9898
write_config_file(ofs, argv[0]);
99+
exit(0);
100+
}
101+
102+
auto missing_arg = false;
103+
for (auto it = Args::arg_begin(); it != Args::arg_end(); ++it) {
104+
auto arg = *it;
105+
assert(!(arg->is_required() && arg->has_default()) && "Arguments cannot be both required and have a default.");
106+
if (arg->is_required() && !arg->has_been_provided()) {
107+
if (!missing_arg) {
108+
std::cerr << "Errors:" << std::endl;
109+
}
110+
missing_arg = true;
111+
std::cerr << " Argument '" << *arg->alias_begin() << "' is required!" << std::endl;
112+
}
113+
}
114+
if (missing_arg) {
115+
exit(1);
99116
}
100117
}
101118

@@ -173,24 +190,55 @@ class CommandLineConfig {
173190
}
174191

175192
/** Prints arg aliases, usages, and descriptions */
176-
static void write_help(std::ostream& os) {
193+
static void write_help(std::ostream& os, bool show_defaults_in_Help) {
177194
ofilterstream<Indent> ofs(os);
178195
ofs.filter().indent();
179196

197+
auto show_defaults = show_defaults_in_Help;
198+
180199
for (auto g = Args::group_begin(); g != Args::group_end(); ++g) {
181200
ofs << g->heading() << std::endl;
182201
ofs << std::endl;
183202
for (auto a = g->arg_begin(); a != g->arg_end(); ++a) {
203+
std::string default_val;
204+
bool short_default = false;
205+
bool default_has_newline = false;
206+
184207
write_arg(ofs, *a);
185-
ofs << std::endl;
186208

209+
if (show_defaults && (*a)->has_default()) {
210+
std::ostringstream ss;
211+
(*a)->debug(ss);
212+
default_val = ss.str();
213+
if (default_val.find("\n") != std::string::npos) {
214+
default_has_newline = true;
215+
} else if (default_val.length() < 20) {
216+
short_default = true;
217+
ofs << " (default: " << default_val << ")";
218+
}
219+
}
220+
221+
ofs << std::endl;
187222
ofs.filter().indent(2);
188223

189224
ofilterstream<Wrap> wrap(ofs);
190225
wrap.filter().limit(60);
191226
(*a)->description(wrap);
192227
wrap << std::endl;
193228

229+
// try to print the default value
230+
if (show_defaults && !short_default && (*a)->has_default()) {
231+
if (!default_has_newline && default_val.length() < 150) {
232+
// only show default argument if the default does not take more than one line
233+
wrap << "Default: " << default_val << std::endl;
234+
} else {
235+
wrap << "Default: use --debug_args to see this default" << std::endl;
236+
}
237+
}
238+
if ((*a)->is_required()) {
239+
wrap << "Required argument" << std::endl;
240+
}
241+
194242
ofs.filter().unindent(2);
195243
}
196244
ofs << std::endl;
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Please sign in to comment.