Port tools to cxxopts (#904)

* Port tools to cxxopts

* Fix minify tool architecture argument

* Fix wrong return code in json2json

* Change return codes

* Better handling of the errors.

* Updating to latest version.

* cxxopts outside of SIMDJSON_COMPETITION

Co-authored-by: Daniel Lemire <lemire@gmail.com>
This commit is contained in:
yoannlr
2020-05-29 21:39:23 +02:00
committed by GitHub
parent ac0c3093f4
commit f772bf4fbc
7 changed files with 171 additions and 126 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
link_libraries(simdjson simdjson-internal-flags simdjson-windows-headers)
link_libraries(simdjson simdjson-internal-flags simdjson-windows-headers cxxopts)
add_executable(json2json json2json.cpp)
add_executable(jsonstats jsonstats.cpp)
+46 -27
View File
@@ -1,40 +1,53 @@
#include <iostream>
#include <unistd.h>
#include "simdjson.h"
#ifndef __cpp_exceptions
#define CXXOPTS_NO_EXCEPTIONS
#endif
#include "cxxopts.hpp"
void usage(const char *exe) {
std::cerr << exe << " v" << STRINGIFY(SIMDJSON_VERSION) << " (" << simdjson::active_implementation->name() << ")" << std::endl;
std::cerr << std::endl;
std::cerr << "Reads json in, out the result of the parsing. " << std::endl;
std::cerr << "Usage: " << exe << " <jsonfile>" << std::endl;
std::cerr << "The -d flag dumps the raw content of the tape." << std::endl;
}
int main(int argc, char *argv[]) {
bool rawdump = false;
#ifdef __cpp_exceptions
try {
#endif
std::string progName = "json2json";
int c;
std::string progUsage = "json2json version ";
progUsage += STRINGIFY(SIMDJSON_VERSION);
progUsage += " (";
progUsage += simdjson::active_implementation->name();
progUsage += ")\n";
progUsage += "Reads json in, out the result of the parsing.\n";
progUsage += argv[0];
progUsage += " <jsonfile>\n";
while ((c = getopt(argc, argv, "dh")) != -1) {
switch (c) {
case 'd':
rawdump = true;
break;
case 'h':
usage(argv[0]);
return EXIT_SUCCESS;
default:
abort();
}
cxxopts::Options options(progName, progUsage);
options.add_options()
("d,rawdump", "Dumps the raw content of the tape.", cxxopts::value<bool>()->default_value("false"))
("f,file", "File name.", cxxopts::value<std::string>())
("h,help", "Print usage.")
;
// the first argument without an option name will be parsed into file
options.parse_positional({"file"});
auto result = options.parse(argc, argv);
if(result.count("help")) {
std::cerr << options.help() << std::endl;
return EXIT_SUCCESS;
}
if (optind >= argc) {
usage(argv[0]);
bool rawdump = result["rawdump"].as<bool>();
if(!result.count("file")) {
std::cerr << "No filename specified." << std::endl;
std::cerr << options.help() << std::endl;
return EXIT_FAILURE;
}
const char *filename = argv[optind];
if (optind + 1 < argc) {
std::cerr << "warning: ignoring everything after " << argv[optind + 1]
<< std::endl;
}
const char *filename = result["file"].as<std::string>().c_str();
simdjson::dom::parser parser;
auto [doc, error] = parser.load(filename); // do the parsing, return false on error
if (error != simdjson::SUCCESS) {
@@ -48,4 +61,10 @@ int main(int argc, char *argv[]) {
std::cout << doc;
}
return EXIT_SUCCESS;
#ifdef __cpp_exceptions
} catch (const cxxopts::OptionException& e) {
std::cout << "error parsing options: " << e.what() << std::endl;
return EXIT_FAILURE;
}
#endif
}
+65 -36
View File
@@ -2,6 +2,10 @@
#include <set>
#include "simdjson.h"
#ifndef __cpp_exceptions
#define CXXOPTS_NO_EXCEPTIONS
#endif
#include "cxxopts.hpp"
size_t count_nonasciibytes(const uint8_t *input, size_t length) {
size_t count = 0;
@@ -180,18 +184,37 @@ stat_t simdjson_compute_stats(const simdjson::padded_string &p) {
}
int main(int argc, char *argv[]) {
int myoptind = 1;
if (myoptind >= argc) {
std::cerr << "Reads json, prints stats. " << std::endl;
std::cerr << "Usage: " << argv[0] << " <jsonfile>" << std::endl;
exit(1);
#ifdef __cpp_exceptions
try {
#endif
std::string progName = "jsonstat";
std::string progUsage = "Reads json, prints stats.\n";
progUsage += argv[0];
progUsage += " <jsonfile>";
cxxopts::Options options(progName, progUsage);
options.add_options()
("h,help", "Print usage.")
("f,file", "File name.", cxxopts::value<std::string>())
;
options.parse_positional({"file"});
auto result = options.parse(argc, argv);
if(result.count("help")) {
std::cerr << options.help() << std::endl;
return EXIT_SUCCESS;
}
const char *filename = argv[myoptind];
if (myoptind + 1 < argc) {
std::cerr << "warning: ignoring everything after " << argv[myoptind + 1]
<< std::endl;
if(!result.count("file")) {
std::cerr << "No filename specified." << std::endl;
std::cerr << options.help() << std::endl;
return EXIT_FAILURE;
}
const char *filename = result["file"].as<std::string>().c_str();
auto [p, error] = simdjson::padded_string::load(filename);
if (error) {
std::cerr << "Could not load the file " << filename << std::endl;
@@ -206,33 +229,33 @@ int main(int argc, char *argv[]) {
// a JSON object and then to serialize it.
printf(R"({
"integer_count" = %10zu,
"integer32_count" = %10zu,
"unsigned_integer32_count" = %10zu,
"unsigned_integer_count" = %10zu,
"float_count" = %10zu,
"string_count" = %10zu,
"string_byte_count" = %10zu,
"ascii_string_count" = %10zu,
"string_maximum_length" = %10zu,
"backslash_count" = %10zu,
"non_ascii_byte_count" = %10zu,
"object_count" = %10zu,
"maximum_object_size" = %10zu,
"array_count" = %10zu,
"maximum_array_size" = %10zu,
"null_count" = %10zu,
"true_count" = %10zu,
"false_count" = %10zu,
"byte_count" = %10zu,
"structural_indexes_count" = %10zu,
"key_count" = %10zu,
"ascii_key_count" = %10zu,
"key_maximum_length" = %10zu,
"key_distinct_count" = %10zu,
"integer_count" = %10zu,
"integer32_count" = %10zu,
"unsigned_integer32_count" = %10zu,
"unsigned_integer_count" = %10zu,
"float_count" = %10zu,
"string_count" = %10zu,
"string_byte_count" = %10zu,
"ascii_string_count" = %10zu,
"string_maximum_length" = %10zu,
"backslash_count" = %10zu,
"non_ascii_byte_count" = %10zu,
"object_count" = %10zu,
"maximum_object_size" = %10zu,
"array_count" = %10zu,
"maximum_array_size" = %10zu,
"null_count" = %10zu,
"true_count" = %10zu,
"false_count" = %10zu,
"byte_count" = %10zu,
"structural_indexes_count" = %10zu,
"key_count" = %10zu,
"ascii_key_count" = %10zu,
"key_maximum_length" = %10zu,
"key_distinct_count" = %10zu,
"repeated_key_distinct_count"= %10zu,
"repeated_key_byte_count" = %10zu;
"maximum_depth" = %10zu
"repeated_key_byte_count" = %10zu;
"maximum_depth" = %10zu
}
)",
s.integer_count,s.integer32_count,s.unsigned_integer32_count,s.unsigned_integer_count,
@@ -244,4 +267,10 @@ int main(int argc, char *argv[]) {
s.ascii_key_count, s.key_maximum_length, s.all_keys.size(), s.repeated_keys.size(),
s.repeated_key_byte_count, s.maximum_depth);
return EXIT_SUCCESS;
}
#ifdef __cpp_exceptions
} catch (const cxxopts::OptionException& e) {
std::cout << "error parsing options: " << e.what() << std::endl;
return EXIT_FAILURE;
}
#endif
}
+51 -62
View File
@@ -5,74 +5,57 @@
#include <unistd.h>
#include "simdjson.h"
#ifndef __cpp_exceptions
#define CXXOPTS_NO_EXCEPTIONS
#endif
#include "cxxopts.hpp"
// Stash the exe_name in main() for functions to use
char* exe_name;
cxxopts::Options options("minify", "Runs the parser against the given json files in a loop, measuring speed and other statistics.");
void print_usage(std::ostream& out) {
out << "Usage: " << exe_name << " [-a ARCH] <jsonfile>" << std::endl;
out << std::endl;
out << "Runs the parser against the given json files in a loop, measuring speed and other statistics." << std::endl;
out << std::endl;
out << "Options:" << std::endl;
out << std::endl;
out << "-a IMPL - Use the given parser implementation. By default, detects the most advanced" << std::endl;
out << " implementation supported on the host machine." << std::endl;
for (auto impl : simdjson::available_implementations) {
out << "-a " << std::left << std::setw(9) << impl->name() << " - Use the " << impl->description() << " parser implementation." << std::endl;
}
}
void exit_usage(std::string message) {
void usage(std::string message) {
std::cerr << message << std::endl;
std::cerr << std::endl;
print_usage(std::cerr);
exit(EXIT_FAILURE);
std::cerr << options.help() << std::endl;
}
struct option_struct {
char* filename{};
option_struct(int argc, char **argv) {
int c;
while ((c = getopt(argc, argv, "a:")) != -1) {
switch (c) {
case 'a': {
const simdjson::implementation *impl = simdjson::available_implementations[optarg];
if (!impl) {
std::string exit_message = std::string("Unsupported option value -a ") + optarg + ": expected -a with one of ";
for (auto imple : simdjson::available_implementations) {
exit_message += imple->name();
exit_message += " ";
}
exit_usage(exit_message);
}
simdjson::active_implementation = impl;
break;
}
default:
// reaching here means an argument was given to getopt() which did not have a case label
exit_usage("Unexpected argument - missing case for option "+
std::string(1,static_cast<char>(c))+
" (programming error)");
}
}
// All remaining arguments are considered to be files
if(optind + 1 == argc) {
filename = argv[optind];
} else {
exit_usage("Please specify exactly one input file.");
}
}
};
int main(int argc, char *argv[]) {
exe_name = argv[0];
option_struct options(argc, argv);
std::string filename = options.filename;
#ifdef __cpp_exceptions
try {
#endif
std::stringstream ss;
ss << "Parser implementation (by default, detects the most advanced implementation supported on the host machine)." << std::endl;
ss << "Available parser implementations:" << std::endl;
for (auto impl : simdjson::available_implementations) {
ss << "-a " << std::left << std::setw(9) << impl->name() << " - Use the " << impl->description() << " parser implementation." << std::endl;
}
options.add_options()
("a,arch", ss.str(), cxxopts::value<std::string>())
("f,file", "File name.", cxxopts::value<std::string>())
("h,help", "Print usage.")
;
options.parse_positional({"file"});
auto result = options.parse(argc, argv);
if(result.count("help")) {
usage("");
return EXIT_SUCCESS;
}
if(!result.count("file")) {
usage("No filename specified.");
return EXIT_FAILURE;
}
if(result.count("arch")) {
const simdjson::implementation *impl = simdjson::available_implementations[result["arch"].as<std::string>().c_str()];
if(!impl) {
usage("Unsupported implementation.");
return EXIT_FAILURE;
}
simdjson::active_implementation = impl;
}
std::string filename = result["file"].as<std::string>();
auto [p, error] = simdjson::padded_string::load(filename);
if (error) {
std::cerr << "Could not load the file " << filename << std::endl;
@@ -83,4 +66,10 @@ int main(int argc, char *argv[]) {
error = simdjson::active_implementation->minify((const uint8_t*)p.data(), p.length(), (uint8_t*)copy.data(), copy_len);
if (error) { std::cerr << error << std::endl; return 1; }
printf("%s", copy.data());
#ifdef __cpp_exceptions
} catch (const cxxopts::OptionException& e) {
std::cout << "error parsing options: " << e.what() << std::endl;
return EXIT_FAILURE;
}
#endif
}