Skip to content

Commit

Permalink
Release v2.0
Browse files Browse the repository at this point in the history
Merge branch 'release-2.0'
  • Loading branch information
eschkufz committed Jan 6, 2015
2 parents ff85128 + 20c7f39 commit e7b99c1
Show file tree
Hide file tree
Showing 17 changed files with 613 additions and 32 deletions.
3 changes: 3 additions & 0 deletions examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ EX = command_line/command_line \
container/maputil \
container/tokenizer \
debug/stl_print \
io/abort \
io/column \
io/filterstream \
io/indent \
io/line_comment \
io/multistream \
io/prefix \
io/redact \
io/redirectstream \
io/shunt \
Expand All @@ -41,6 +43,7 @@ EX = command_line/command_line \
meta/indices \
patterns/singleton \
serialize/hex \
serialize/line \
serialize/text \
signal/debug_handler \
system/terminal
Expand Down
2 changes: 1 addition & 1 deletion examples/command_line/command_line.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ auto& i = ValueArg<int, RangeReader<int, Range<int, 1, 10>>>::create("i")
.alternate("int")
.usage("<int>")
.description("i | 1 <= i <= 10")
.default_val(5);
.required();

auto& h = ValueArg<uint64_t, HexReader<uint64_t>, HexWriter<uint64_t>>::create("j")
.alternate("hex")
Expand Down
31 changes: 31 additions & 0 deletions examples/io/abort.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2014 eric schkufza
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <iostream>
#include <string>

#include "include/io/filterstream.h"
#include "include/io/abort.h"

using namespace cpputil;
using namespace std;

int main() {
ofilterstream<Abort> os(cout);
os.filter().code(1);

os << "You should see this..." << endl << "... but not this" << endl;

return 0;
}
31 changes: 31 additions & 0 deletions examples/io/prefix.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2014 eric schkufza
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <iostream>
#include <string>

#include "include/io/filterstream.h"
#include "include/io/prefix.h"

using namespace cpputil;
using namespace std;

int main() {
ofilterstream<Prefix> os(cout);
os.filter().prefix("Hello world: ");

os << "This is" << endl << "a " << endl << "multi-line message" << endl;

return 0;
}
36 changes: 36 additions & 0 deletions examples/serialize/line.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2014 eric schkufza
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <iostream>
#include <sstream>
#include <string>

#include "include/serialize/line_reader.h"

using namespace cpputil;
using namespace std;

int main() {
stringstream ss;
ss << "Line 1: You should see this." << endl;
ss << "Line 2: You shouldn't see this." << endl;

string s;
LineReader<> lr;
lr(ss, s);

cout << s << endl;

return 0;
}
30 changes: 22 additions & 8 deletions include/bits/bit_manip.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@
#define CPPUTIL_INCLUDE_BITS_BIT_MANIP_H

#include <cassert>
#include <stdint.h>

#include <immintrin.h>
#include <stdint.h>

namespace cpputil {

Expand All @@ -30,19 +29,34 @@ class BitManip<uint64_t> {
public:
static size_t ntz(uint64_t x) {
#ifdef __BMI__
return _tzcnt_u64(x);
return __builtin_ctzll(x);
#else
assert(false);
return 0;
// See https://graphics.stanford.edu/~seander/bithacks.html
uint64_t res = 64;
x &= -((int64_t)x);
if (x) res--;
if (x & 0x00000000ffffffff) res -= 32;
if (x & 0x0000ffff0000ffff) res -= 16;
if (x & 0x00ff00ff00ff00ff) res -= 8;
if (x & 0x0f0f0f0f0f0f0f0f) res -= 4;
if (x & 0x3333333333333333) res -= 2;
if (x & 0x5555555555555555) res -= 1;
return res;
#endif
}

static size_t pop_count(uint64_t x) {
#ifdef __POPCNT__
return _popcnt64(x);
return __builtin_popcountll(x);
#else
assert(false);
return 0;
// See https://graphics.stanford.edu/~seander/bithacks.html
uint64_t res = x - ((x >> 1) & 0x5555555555555555);
res = ((res >> 2) & 0x3333333333333333) + (res & 0x3333333333333333);
res = ((res >> 4) + res) & 0x0f0f0f0f0f0f0f0f;
res = ((res >> 8) + res) & 0x00ff00ff00ff00ff;
res = ((res >> 16) + res) & 0x0000ffff0000ffff;
res = ((res >> 32) + res) & 0x00000000ffffffff;
return res;
#endif
}

Expand Down
39 changes: 38 additions & 1 deletion include/command_line/arg.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,21 @@ class Arg {
os << error_;
}

/** Is this argument required? */
bool is_required() const {
return required_;
}

/** Has this argument been set (or does it have a default value)? */
bool has_been_provided() const {
return is_provided_;
}

/** Does this argument have a default? */
bool has_default() const {
return has_default_;
}

/** Prints the value of an arg */
virtual void debug(std::ostream& os) const = 0;

Expand All @@ -100,11 +115,12 @@ class Arg {
};

/** An arg must be assigned at least one alias */
Arg(const std::string& opt) {
Arg(const std::string& opt) : is_provided_(false), has_default_(false) {
alternate(opt);
usage("");
description("(no description provided)");
error("");
required(false);

auto& ar = Singleton<ArgRegistry>::get();
ar.insert(this);
Expand Down Expand Up @@ -166,6 +182,21 @@ class Arg {
error_ = error;
}

/** Reset the required argument. */
void required(const bool val = true) {
required_ = val;
}

/** Reset whether this argument has a default. */
void set_has_default(const bool val = true) {
has_default_ = val;
}

/** Indicate that this argument has been set now. */
void set_provided() {
is_provided_ = true;
}

private:
/** Aliases for this arg ,ie: "-h --help" */
std::set<std::string> opts_;
Expand All @@ -178,6 +209,12 @@ class Arg {
std::string description_;
/** A non-empty value here indicates that a survivable error occurred */
std::string error_;
/** Is this argument mandatory? */
bool required_;
/** Has this argument been provided in some way? */
bool is_provided_;
/** Does this argument have a default? */
bool has_default_;
};

} // namespace cpputil
Expand Down
1 change: 1 addition & 0 deletions include/command_line/command_line.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "include/command_line/command_line_config.h"
#include "include/command_line/file_arg.h"
#include "include/command_line/flag_arg.h"
#include "include/command_line/folder_arg.h"
#include "include/command_line/heading.h"
#include "include/command_line/value_arg.h"

Expand Down
66 changes: 57 additions & 9 deletions include/command_line/command_line_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ namespace cpputil {
class CommandLineConfig {
public:
/** Strict parse with help, config, and debug support */
static void strict_with_convenience(int argc, char** argv) {
static void strict_with_convenience(int argc, char** argv, bool sort_args = false, bool show_defaults_in_Help = true) {
Heading::create("Help and argument utilities:");
auto& help = FlagArg::create("h")
.alternate("help")
Expand All @@ -41,23 +41,23 @@ class CommandLineConfig {
.description("Print program arguments and quit");
auto& read_config = ValueArg<std::string>::create("config")
.usage("<path/to/file.conf>")
.default_val("")
.description("Read program args from a configuration file");
auto& write_config = ValueArg<std::string>::create("example_config")
.usage("<path/to/file.conf>")
.default_val("")
.description("Print an example configuration file");

Args::sort_args([](Arg * a1, Arg * a2) {
return *(a1->alias_begin()) < *(a2->alias_begin());
});
if (sort_args) {
Args::sort_args([](Arg * a1, Arg * a2) {
return *(a1->alias_begin()) < *(a2->alias_begin());
});
}
Args::read(argc, argv);

if (help) {
std::cout << std::endl;
std::cout << "Usage: " << argv[0] << " [options]" << std::endl;
std::cout << std::endl;
write_help(std::cout);
write_help(std::cout, show_defaults_in_Help);
exit(0);
}

Expand Down Expand Up @@ -96,6 +96,23 @@ class CommandLineConfig {
exit(1);
}
write_config_file(ofs, argv[0]);
exit(0);
}

auto missing_arg = false;
for (auto it = Args::arg_begin(); it != Args::arg_end(); ++it) {
auto arg = *it;
assert(!(arg->is_required() && arg->has_default()) && "Arguments cannot be both required and have a default.");
if (arg->is_required() && !arg->has_been_provided()) {
if (!missing_arg) {
std::cerr << "Errors:" << std::endl;
}
missing_arg = true;
std::cerr << " Argument '" << *arg->alias_begin() << "' is required!" << std::endl;
}
}
if (missing_arg) {
exit(1);
}
}

Expand Down Expand Up @@ -173,24 +190,55 @@ class CommandLineConfig {
}

/** Prints arg aliases, usages, and descriptions */
static void write_help(std::ostream& os) {
static void write_help(std::ostream& os, bool show_defaults_in_Help) {
ofilterstream<Indent> ofs(os);
ofs.filter().indent();

auto show_defaults = show_defaults_in_Help;

for (auto g = Args::group_begin(); g != Args::group_end(); ++g) {
ofs << g->heading() << std::endl;
ofs << std::endl;
for (auto a = g->arg_begin(); a != g->arg_end(); ++a) {
std::string default_val;
bool short_default = false;
bool default_has_newline = false;

write_arg(ofs, *a);
ofs << std::endl;

if (show_defaults && (*a)->has_default()) {
std::ostringstream ss;
(*a)->debug(ss);
default_val = ss.str();
if (default_val.find("\n") != std::string::npos) {
default_has_newline = true;
} else if (default_val.length() < 20) {
short_default = true;
ofs << " (default: " << default_val << ")";
}
}

ofs << std::endl;
ofs.filter().indent(2);

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

// try to print the default value
if (show_defaults && !short_default && (*a)->has_default()) {
if (!default_has_newline && default_val.length() < 150) {
// only show default argument if the default does not take more than one line
wrap << "Default: " << default_val << std::endl;
} else {
wrap << "Default: use --debug_args to see this default" << std::endl;
}
}
if ((*a)->is_required()) {
wrap << "Required argument" << std::endl;
}

ofs.filter().unindent(2);
}
ofs << std::endl;
Expand Down
Loading

0 comments on commit e7b99c1

Please sign in to comment.