From 941a7cb1eb5a1cc671b8a794740802e59c5156ff Mon Sep 17 00:00:00 2001 From: Joseph LaFreniere Date: Thu, 21 Dec 2023 14:37:12 -0600 Subject: [PATCH 1/3] Enable clang-format pre-commit hook --- .clang-format | 15 +++++++++++++++ .editorconfig | 5 +++++ flake.nix | 4 ++++ 3 files changed, 24 insertions(+) create mode 100644 .clang-format create mode 100644 .editorconfig diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..853e162 --- /dev/null +++ b/.clang-format @@ -0,0 +1,15 @@ +--- +BasedOnStyle: LLVM +Cpp11BracedListStyle: true +IndentWidth: 4 +AlignAfterOpenBracket: BlockIndent +BreakBeforeBraces: Custom +BraceWrapping: + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterStruct: true + BeforeElse: true + SplitEmptyFunction: false +BinPackParameters: false +BreakBeforeBraces: Allman diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..379209e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[*.cpp] +indent_size = 4 +indent_style = space diff --git a/flake.nix b/flake.nix index 1dc4806..531e871 100644 --- a/flake.nix +++ b/flake.nix @@ -67,6 +67,10 @@ check.enable = true; settings.hooks = { alejandra.enable = true; + clang-format = { + enable = true; + excludes = ["extern/.*"]; + }; }; }; From cb29055ea3cca28972cd564025cee777d7b0b1d7 Mon Sep 17 00:00:00 2001 From: Joseph LaFreniere Date: Sat, 6 Jan 2024 09:07:51 -0600 Subject: [PATCH 2/3] Apply clang-format --- src/batched_print.hpp | 5 +- src/builder.hpp | 4 +- src/fastgron.cpp | 103 ++++++++++++++++++++---------- src/growing_string.hpp | 30 +++------ src/jsonutils.hpp | 14 ++--- src/parse_gron.cpp | 35 ++++++++--- src/parse_gron.hpp | 10 ++- src/parse_path.cpp | 121 ++++++++++++++++++++++-------------- src/parse_path.hpp | 72 ++++++++++++--------- src/print_filtered_path.cpp | 96 +++++++++++++++++++++------- src/print_filtered_path.hpp | 13 ++-- src/print_gron.cpp | 48 ++++++++++---- src/print_gron.hpp | 24 ++++--- src/print_json.cpp | 14 +++-- src/print_json.hpp | 2 +- src/test.json | 4 +- test2.json | 6 +- 17 files changed, 387 insertions(+), 214 deletions(-) diff --git a/src/batched_print.hpp b/src/batched_print.hpp index 130519b..fe73ca9 100644 --- a/src/batched_print.hpp +++ b/src/batched_print.hpp @@ -46,10 +46,7 @@ inline void batched_print(string_view s) batched_print_flush_if_needed(); } -inline void batched_print_no_flush(string_view s) -{ - batched_out.append(s); -} +inline void batched_print_no_flush(string_view s) { batched_out.append(s); } inline void batched_print(char c) { diff --git a/src/builder.hpp b/src/builder.hpp index cf2d46c..72b2232 100644 --- a/src/builder.hpp +++ b/src/builder.hpp @@ -1,10 +1,10 @@ #pragma once -#include +#include #include +#include #include #include -#include using std::string; using std::string_view; diff --git a/src/fastgron.cpp b/src/fastgron.cpp index dff8ac4..712af45 100644 --- a/src/fastgron.cpp +++ b/src/fastgron.cpp @@ -1,14 +1,14 @@ #include "simdjson.h" +#include +#include // for strcmp #include #include +#include #include -#include -#include #include -#include -#include // for strcmp -#include #include +#include +#include #include #ifndef FASTGRON_VERSION @@ -34,12 +34,12 @@ using namespace std; string out; -#include "growing_string.hpp" #include "batched_print.hpp" +#include "growing_string.hpp" #include "jsonutils.hpp" -#include "print_gron.hpp" -#include "print_filtered_path.hpp" #include "parse_gron.hpp" +#include "print_filtered_path.hpp" +#include "print_gron.hpp" #include "print_json.hpp" // Parse command-line options @@ -70,8 +70,10 @@ bool is_url(string_view url) void print_simdjson_version() { cerr << "simdjson v" << SIMDJSON_VERSION << endl; - cerr << " Detected the best implementation for your machine: " << simdjson::get_active_implementation()->name(); - cerr << "(" << simdjson::get_active_implementation()->description() << ")" << endl; + cerr << " Detected the best implementation for your machine: " + << simdjson::get_active_implementation()->name(); + cerr << "(" << simdjson::get_active_implementation()->description() << ")" + << endl; } growing_string indent = ""; @@ -96,17 +98,24 @@ void print_help() " -V, --version show version information and exit\n" " -s, --stream enable stream mode\n" " -F, --fixed-string PATTERN filter output by fixed string.\n" - " If -F is provided multiple times, multiple patterns are searched.\n" - " -v, --invert-match select non-matching lines for fixed string search\n" + " If -F is provided multiple times, multiple " + "patterns are searched.\n" + " -v, --invert-match select non-matching lines for fixed string " + "search\n" " -i, --ignore-case ignore case distinctions in PATTERN\n" " --sort sort output by key\n" " --user-agent set user agent\n" - " --header Name:value set custom HTTP header, can be used multiple times\n" + " --header Name:value set custom HTTP header, can be used " + "multiple times\n" " -u, --ungron ungron: convert gron output back to JSON\n" - " -p, -path filter path, for example .#.3.population or cities.#.population\n" - " -p is optional if path starts with . and file with that name doesn't exist\n" - " More complex path expressions: .{id,users[1:-3:2].{name,address}}\n" - " [[3]] is an index accessor without outputting on the path.\n" + " -p, -path filter path, for example .#.3.population or " + "cities.#.population\n" + " -p is optional if path starts with . and file with " + "that name doesn't exist\n" + " More complex path expressions: " + ".{id,users[1:-3:2].{name,address}}\n" + " [[3]] is an index accessor without outputting on the " + "path.\n" " --no-indent don't indent output\n" " --no-newline no newline inside JSON output\n" " --root root path, default is json\n" @@ -114,8 +123,10 @@ void print_help() " --no-spaces don't add spaces around =\n" " -c, --color colorize output\n" " --no-color don't colorize output\n" - "\nHome page with more information: https://github.com/adamritter/fastgron\n" - "\nIf you have a feature that would help you, open an issue here:\nhttps://github.com/adamritter/fastgron/issues\n"; + "\nHome page with more information: " + "https://github.com/adamritter/fastgron\n" + "\nIf you have a feature that would help you, open an issue " + "here:\nhttps://github.com/adamritter/fastgron/issues\n"; } void print_version() @@ -214,7 +225,8 @@ std::string download(options opts) if (res != CURLE_OK) { const char *curl_err_msg = curl_easy_strerror(res); - cerr << "Error when downloading data: " << string(curl_err_msg) << "\n"; + cerr << "Error when downloading data: " << string(curl_err_msg) + << "\n"; exit(EXIT_FAILURE); } free(s.ptr); @@ -363,7 +375,8 @@ options parse_options(int argc, char *argv[]) } else { - if (!is_url(argv[i]) && access(argv[i], F_OK) == -1 && argv[i] != string("-")) + if (!is_url(argv[i]) && access(argv[i], F_OK) == -1 && + argv[i] != string("-")) { // Treat strings starting with . as paths if (argv[i][0] == '.') @@ -400,8 +413,10 @@ int main(int argc, char *argv[]) { for (auto &filter : filters) { - std::transform(filter.begin(), filter.end(), filter.begin(), [](unsigned char c) - { return fast_tolower(c); }); + std::transform( + filter.begin(), filter.end(), filter.begin(), + [](unsigned char c) { return fast_tolower(c); } + ); } } @@ -429,7 +444,8 @@ int main(int argc, char *argv[]) // Load string from stdin json = padded_string(readFileIntoString(0)); } - else if (curl_found && opts.filename.compare(0, 7, "http://") == 0 || opts.filename.compare(0, 8, "https://") == 0) + else if (curl_found && opts.filename.compare(0, 7, "http://") == 0 || + opts.filename.compare(0, 8, "https://") == 0) { json = padded_string(download(opts)); } @@ -463,31 +479,48 @@ int main(int argc, char *argv[]) string_view line = string_view(data, end - data); // find commonality with last line int common = 0; - while (common < line.size() && common < last_line.size() && line[common] == last_line[common]) + while (common < line.size() && common < last_line.size() && + line[common] == last_line[common]) { common++; } // if it's not a token ending, make sure we don't use the last token - if (common < line.size() && line[common] != ' ' && line[common] != '=' && line[common] != '.' && line[common] != '[') + if (common < line.size() && line[common] != ' ' && + line[common] != '=' && line[common] != '.' && + line[common] != '[') { common--; } int index = 0; - while (index < parse_gron_builder_offsets.size() && parse_gron_builder_offsets[index] <= common) + while (index < parse_gron_builder_offsets.size() && + parse_gron_builder_offsets[index] <= common) { index++; } - parse_gron_builders.erase(parse_gron_builders.begin() + index, parse_gron_builders.end()); - parse_gron_builder_offsets.erase(parse_gron_builder_offsets.begin() + index, parse_gron_builder_offsets.end()); - Builder &passed_builder = parse_gron_builders.empty() ? builder : *parse_gron_builders.back(); - int offset = parse_gron_builders.empty() ? 0 : parse_gron_builder_offsets.back(); - parse_gron(line.substr(offset), passed_builder, offset, parse_gron_builders, parse_gron_builder_offsets); + parse_gron_builders.erase( + parse_gron_builders.begin() + index, parse_gron_builders.end() + ); + parse_gron_builder_offsets.erase( + parse_gron_builder_offsets.begin() + index, + parse_gron_builder_offsets.end() + ); + Builder &passed_builder = parse_gron_builders.empty() + ? builder + : *parse_gron_builders.back(); + int offset = parse_gron_builders.empty() + ? 0 + : parse_gron_builder_offsets.back(); + parse_gron( + line.substr(offset), passed_builder, offset, + parse_gron_builders, parse_gron_builder_offsets + ); // parse_gron(line, builder, 0); last_line = line; data = end + 1; } - if (std::holds_alternative(builder) && std::get(builder) == "") + if (std::holds_alternative(builder) && + std::get(builder) == "") { cerr << "Builder is not assigned\n"; return EXIT_FAILURE; @@ -506,7 +539,9 @@ int main(int argc, char *argv[]) else { // Error: not a stream - cerr << "Error: input gron file must be an array to be able to output a stream\n"; + cerr << "Error: input gron file must be an array to be able to " + "output " + "a stream\n"; } } else diff --git a/src/growing_string.hpp b/src/growing_string.hpp index 77a62f8..1cd25d6 100644 --- a/src/growing_string.hpp +++ b/src/growing_string.hpp @@ -1,23 +1,21 @@ #pragma once -#include #include #include +#include using std::max; using std::string_view; // Provides a dynamic string storage that grows as needed. -// Unlike std::string, it doesn't shrink the allocated storage capacity when the end of the string is erased. +// Unlike std::string, it doesn't shrink the allocated storage capacity when the +// end of the string is erased. struct growing_string { char *data; size_t len = 0; size_t capacity; - growing_string() : capacity(1000) - { - data = new char[capacity]; - } + growing_string() : capacity(1000) { data = new char[capacity]; } bool starts_with(string_view s) const { @@ -41,10 +39,7 @@ struct growing_string memcpy(data, s, len); } - ~growing_string() - { - delete[] data; - } + ~growing_string() { delete[] data; } void reserve_extra(size_t extra) { if (len + extra > capacity) @@ -57,10 +52,7 @@ struct growing_string } } - string_view view() const - { - return std::string_view(data, len); - } + string_view view() const { return std::string_view(data, len); } growing_string &append(string_view s) { @@ -86,15 +78,9 @@ struct growing_string return *this; } - inline size_t size() const - { - return len; - } + inline size_t size() const { return len; } - operator string_view() const - { - return {data, len}; - } + operator string_view() const { return {data, len}; } void clear_mem() { diff --git a/src/jsonutils.hpp b/src/jsonutils.hpp index 08d68a8..b020a65 100644 --- a/src/jsonutils.hpp +++ b/src/jsonutils.hpp @@ -1,8 +1,8 @@ #pragma once -#include +#include #include +#include #include -#include using std::string; using std::string_view; @@ -86,7 +86,6 @@ inline int raw_json_string_length(string_view str) return -1; } - // Returns -1 if end is reached before closing quote inline int raw_json_string_length(const char *s) { @@ -124,7 +123,8 @@ inline int raw_json_string_length(const char *s) return -1; } -inline bool can_show(string_view s, const unsigned flags, vector &filters) +inline bool +can_show(string_view s, const unsigned flags, vector &filters) { if (!filters.empty()) { @@ -135,10 +135,10 @@ inline bool can_show(string_view s, const unsigned flags, vector &filter { // std::tolower is slow, and doesn't handle UTF-8 auto it = std::search( - s.begin(), s.end(), - filter.begin(), filter.end(), + s.begin(), s.end(), filter.begin(), filter.end(), [](unsigned char ch1, unsigned char ch2) - { return fast_tolower(ch1) == (ch2); }); + { return fast_tolower(ch1) == (ch2); } + ); if (it != s.end()) { found = true; diff --git a/src/parse_gron.cpp b/src/parse_gron.cpp index 18354a9..de3ed0b 100644 --- a/src/parse_gron.cpp +++ b/src/parse_gron.cpp @@ -1,12 +1,16 @@ -#include #include "parse_gron.hpp" #include "jsonutils.hpp" #include +#include // BUG: ["..."] is not handled -void parse_gron(string_view line, Builder &builder, int offset, - vector &parse_gron_builders, - vector &parse_gron_builder_offsets) +void parse_gron( + string_view line, + Builder &builder, + int offset, + vector &parse_gron_builders, + vector &parse_gron_builder_offsets +) { if (line.empty()) @@ -23,7 +27,8 @@ void parse_gron(string_view line, Builder &builder, int offset, // find end of key size_t end = 1; - while (end < line.size() && line[end] != '[' && line[end] != '=' && line[end] != ' ' && line[end] != '.') + while (end < line.size() && line[end] != '[' && line[end] != '=' && + line[end] != ' ' && line[end] != '.') { end++; } @@ -35,7 +40,10 @@ void parse_gron(string_view line, Builder &builder, int offset, } parse_gron_builders.push_back(&child->second); parse_gron_builder_offsets.emplace_back(offset + end); - parse_gron(line.substr(end), child->second, offset + end, parse_gron_builders, parse_gron_builder_offsets); + parse_gron( + line.substr(end), child->second, offset + end, parse_gron_builders, + parse_gron_builder_offsets + ); } else if (line[0] == '[' && line[1] == '"') { @@ -72,7 +80,10 @@ void parse_gron(string_view line, Builder &builder, int offset, } end++; parse_gron_builder_offsets.emplace_back(offset + end); - parse_gron(line.substr(end), child->second, offset + end, parse_gron_builders, parse_gron_builder_offsets); + parse_gron( + line.substr(end), child->second, offset + end, parse_gron_builders, + parse_gron_builder_offsets + ); } else if (line[0] == '[' && isdigit(line[1])) { @@ -97,12 +108,16 @@ void parse_gron(string_view line, Builder &builder, int offset, } parse_gron_builders.push_back(&vector_alt[index]); parse_gron_builder_offsets.emplace_back(offset + end); - parse_gron(line.substr(end), vector_alt[index], offset + end, parse_gron_builders, parse_gron_builder_offsets); + parse_gron( + line.substr(end), vector_alt[index], offset + end, + parse_gron_builders, parse_gron_builder_offsets + ); } else if (line[0] == '=' || (line[0] == ' ' && line[1] == '=')) { size_t start = 1; - while (start < line.size() && (line[start] == ' ' || line[start] == '=')) + while (start < line.size() && (line[start] == ' ' || line[start] == '=') + ) { start++; } @@ -125,4 +140,4 @@ void parse_gron(string_view line, Builder &builder, int offset, builder.emplace(value); } } -} \ No newline at end of file +} diff --git a/src/parse_gron.hpp b/src/parse_gron.hpp index c063975..d975a4d 100644 --- a/src/parse_gron.hpp +++ b/src/parse_gron.hpp @@ -4,6 +4,10 @@ #include using std::vector; -void parse_gron(string_view line, Builder &builder, int offset, - vector &parse_gron_builders, - vector &parse_gron_builder_offsets); +void parse_gron( + string_view line, + Builder &builder, + int offset, + vector &parse_gron_builders, + vector &parse_gron_builder_offsets +); diff --git a/src/parse_path.cpp b/src/parse_path.cpp index 3056762..cf356d8 100644 --- a/src/parse_path.cpp +++ b/src/parse_path.cpp @@ -1,31 +1,29 @@ -#include -#include -#include -#include -#include #include "parse_path.hpp" -#include #include +#include +#include +#include +#include +#include +#include using namespace std; -bool isIdentifierChar(char c) -{ - return std::isalnum(c) || c == '_'; -} +bool isIdentifierChar(char c) { return std::isalnum(c) || c == '_'; } -inline bool isDigitOrMinus(char c) -{ - return std::isdigit(c) || c == '-'; -} +inline bool isDigitOrMinus(char c) { return std::isdigit(c) || c == '-'; } // TODO: Implement batching later void ObjectAccessors::batchOrInsert(ObjectAccessor object_accessor) { - std::vector::iterator it = std::lower_bound(object_accessors.begin(), object_accessors.end(), object_accessor); + std::vector::iterator it = std::lower_bound( + object_accessors.begin(), object_accessors.end(), object_accessor + ); if (it != object_accessors.end()) { - throw std::runtime_error("Cannot insert a value accessor for a key that already exists."); + throw std::runtime_error( + "Cannot insert a value accessor for a key that already exists." + ); } else { @@ -35,24 +33,24 @@ void ObjectAccessors::batchOrInsert(ObjectAccessor object_accessor) class Parser { -public: + public: Parser(const std::string_view &input) : input_(input), index_(0) {} - ValueAccessor parse() - { - return parseValueAccessor(); - } + ValueAccessor parse() { return parseValueAccessor(); } -private: + private: std::string_view lookAhead(int N) { // Ensure we're not exceeding the bounds of the input string. if (index_ + N > input_.size()) { - throw std::runtime_error("Attempted to look ahead beyond the end of input."); + throw std::runtime_error( + "Attempted to look ahead beyond the end of input." + ); } - // Return a view of the next N characters from the input string without advancing the index. + // Return a view of the next N characters from the input string without + // advancing the index. return std::string_view(input_).substr(index_, N); } @@ -61,7 +59,9 @@ class Parser // Ensure we're not exceeding the bounds of the input string. if (index_ + N > input_.size()) { - throw std::runtime_error("Attempted to consume beyond the end of input."); + throw std::runtime_error( + "Attempted to consume beyond the end of input." + ); } // Advance the index by N characters. @@ -83,8 +83,12 @@ class Parser } accessors.object_accessors.emplace_back(parseObjectAccessor()); } - sort(accessors.object_accessors.begin(), accessors.object_accessors.end(), [](const ObjectAccessor &a, const ObjectAccessor &b) - { return a.key < b.key; }); + sort( + accessors.object_accessors.begin(), + accessors.object_accessors.end(), + [](const ObjectAccessor &a, const ObjectAccessor &b) + { return a.key < b.key; } + ); return accessors; } @@ -141,8 +145,11 @@ class Parser ObjectAccessors objectAccessors; string key = parseJSONString(); expect(']'); - objectAccessors.object_accessors.emplace_back(ObjectAccessor{key, nullopt, parseValueAccessor()}); - return std::make_unique(std::move(objectAccessors)); + objectAccessors.object_accessors.emplace_back(ObjectAccessor{ + key, nullopt, parseValueAccessor()}); + return std::make_unique( + std::move(objectAccessors) + ); } else { @@ -153,7 +160,8 @@ class Parser { ObjectAccessors objectAccessors = parseObjectAccessors(); expect('}'); - return std::make_unique(std::move(objectAccessors)); + return std::make_unique(std::move(objectAccessors) + ); } else if (match('.')) { @@ -161,7 +169,9 @@ class Parser { ObjectAccessors objectAccessors = parseObjectAccessors(); expect('}'); - return std::make_unique(std::move(objectAccessors)); + return std::make_unique( + std::move(objectAccessors) + ); } Slice slice; if (match('#')) @@ -182,13 +192,20 @@ class Parser { ObjectAccessor objectAccessor = parseObjectAccessor(); ObjectAccessors objectAccessors; - objectAccessors.object_accessors.emplace_back(std::move(objectAccessor)); - return std::make_unique(std::move(objectAccessors)); + objectAccessors.object_accessors.emplace_back( + std::move(objectAccessor) + ); + return std::make_unique( + std::move(objectAccessors) + ); } else { - throw std::runtime_error("Expected a value accessor, path: " + std::string(input_) + " index: " + std::to_string(index_)); + throw std::runtime_error( + "Expected a value accessor, path: " + std::string(input_) + + " index: " + std::to_string(index_) + ); } } else if (index_ == input_.length() || input_[index_] == ',' || input_[index_] == '}') @@ -197,12 +214,14 @@ class Parser } else { - throw std::runtime_error("Expected a value accessor, path: " + std::string(input_) + " index: " + std::to_string(index_)); + throw std::runtime_error( + "Expected a value accessor, path: " + std::string(input_) + + " index: " + std::to_string(index_) + ); } } - Slice - parseSlice() + Slice parseSlice() { Slice slice; if (match('[')) // Double [ @@ -210,7 +229,10 @@ class Parser slice.append_index = false; if (!tryParseInt(slice.start)) { - throw std::runtime_error("Expected a value accessor, path: " + std::string(input_) + " index: " + std::to_string(index_)); + throw std::runtime_error( + "Expected a value accessor, path: " + std::string(input_) + + " index: " + std::to_string(index_) + ); } expect(']'); slice.end = slice.start + 1; @@ -272,7 +294,9 @@ class Parser skipWhitespace(); if (index_ >= input_.size() || input_[index_] != c) { - throw std::runtime_error("Expected character '" + std::string(1, c) + "' not found."); + throw std::runtime_error( + "Expected character '" + std::string(1, c) + "' not found." + ); } ++index_; } @@ -296,7 +320,7 @@ class Parser } } -private: + private: const std::string_view &input_; std::size_t index_; }; @@ -308,7 +332,8 @@ void debug_print_path(ValueAccessor &valueAccessor); void debug_print_path(Slice &slice) { - cout << "Slice: " << slice.start << " " << slice.end << " " << slice.step << endl; + cout << "Slice: " << slice.start << " " << slice.end << " " << slice.step + << endl; } void debug_print_path(AllAccessor &allAccessor) @@ -341,13 +366,19 @@ void debug_print_path(ValueAccessor &valueAccessor) { debug_print_path(*std::get>(valueAccessor)); } - else if (std::holds_alternative>(valueAccessor)) + else if (std::holds_alternative>( + valueAccessor + )) { - debug_print_path(*std::get>(valueAccessor)); + debug_print_path( + *std::get>(valueAccessor) + ); } - else if (std::holds_alternative>(valueAccessor)) + else if (std::holds_alternative>(valueAccessor + )) { - debug_print_path(*std::get>(valueAccessor)); + debug_print_path(*std::get>(valueAccessor) + ); } } diff --git a/src/parse_path.hpp b/src/parse_path.hpp index b8ae6d6..de77a04 100644 --- a/src/parse_path.hpp +++ b/src/parse_path.hpp @@ -1,23 +1,27 @@ // This file contains the data structure for storing path grammars. // Example paths are: // .a[1].b.2[4:][-3:] that contain slices and object accessors. -// Multiple object accessors can be created like this .{id,users[1].{name,address}} -// It's also equivalent to this: .{id,users[1].name,users[1].address} -// Renaming can be supported multiple ways: -// .{id,user:users[1]:.{name,address}} or .{id,name:users[1].name,address:users[1].address} -// or {.id,user.name:users[1].name,user.address:users[1].address} -// Rewinding or multipath support is needed to support this: +// Multiple object accessors can be created like this +// .{id,users[1].{name,address}} It's also equivalent to this: +// .{id,users[1].name,users[1].address} Renaming can be supported multiple ways: +// .{id,user:users[1]:.{name,address}} or +// .{id,name:users[1].name,address:users[1].address} or +// {.id,user.name:users[1].name,user.address:users[1].address} Rewinding or +// multipath support is needed to support this: // .{id,user:users[1],name:users[1].name,address:users[1].address} // Let's go with multipath. rewriting the last expression looks like this: // .{id,user:users[1]:{name,address}} // [[1]] is an index accessor without outputting on the path. #pragma once -#include #include -#include -#include #include +#include +#include +#include +#include +#include +#include using namespace std; @@ -26,10 +30,11 @@ struct ObjectAccessor; struct ObjectAccessors; struct AllAccessor; -using ValueAccessor = std::variant, - std::unique_ptr, - std::unique_ptr>; +using ValueAccessor = std::variant< + std::monostate, + std::unique_ptr, + std::unique_ptr, + std::unique_ptr>; // Foreach object key or foreach array index struct AllAccessor @@ -62,13 +67,17 @@ struct ObjectAccessor inline ObjectAccessor() = default; - inline ObjectAccessor(std::string key, std::optional new_key, ValueAccessor value_accessor) - : key(key), new_key(new_key), value_accessor(std::move(value_accessor)){}; + inline ObjectAccessor( + std::string key, + std::optional new_key, + ValueAccessor value_accessor + ) + : key(key), new_key(new_key), + value_accessor(std::move(value_accessor)){}; // move constructor inline ObjectAccessor(ObjectAccessor &&other) noexcept - : key(std::move(other.key)), - new_key(std::move(other.new_key)), + : key(std::move(other.key)), new_key(std::move(other.new_key)), value_accessor(std::move(other.value_accessor)){ }; @@ -95,7 +104,8 @@ ValueAccessor parse_path(std::string_view input); /* -// encode the example paths in the given data structure. Don't use helper functions. +// encode the example paths in the given data structure. Don't use helper +functions. // For the path ".a[1].b.2[4:][-3:]" vector getPath1() { @@ -112,26 +122,28 @@ vector getPath1() // For the path ".{id,users[1].name,users[1].address}" vector getPath2() { - Slice sliceForName = {1, 1, 1, true, ObjectAccessor{"name", "name", std::monostate{}}}; - Slice sliceForAddress = {1, 1, 1, true, ObjectAccessor{"address", "address", std::monostate{}}}; - std::vector multipleAccessorsForUsers = {sliceForName, sliceForAddress}; - ObjectAccessor accessorUsers = {"users", "users", multipleAccessorsForUsers}; - std::vector rootAccessors2 = {ObjectAccessor{"id", "id", std::monostate{}}, accessorUsers}; - return rootAccessors2; + Slice sliceForName = {1, 1, 1, true, ObjectAccessor{"name", "name", +std::monostate{}}}; Slice sliceForAddress = {1, 1, 1, true, +ObjectAccessor{"address", "address", std::monostate{}}}; + std::vector multipleAccessorsForUsers = {sliceForName, +sliceForAddress}; ObjectAccessor accessorUsers = {"users", "users", +multipleAccessorsForUsers}; std::vector rootAccessors2 = +{ObjectAccessor{"id", "id", std::monostate{}}, accessorUsers}; return +rootAccessors2; } // For renaming ".{id,user:users[1]:.{name,address}}" vector getPath3() { ValueAccessor inner = {{ObjectAccessor{"name", "name", std::monostate{}}, - ObjectAccessor{"address", "address", std::monostate{}}}, - false}; - Slice sliceForAddressWithRename = {1, 1, 1, false, inner}; - std::vector renamedAccessorsForUsers = {sliceForNameWithRename, sliceForAddressWithRename}; - ObjectAccessor accessorUsersWithRename = {"users", "user", renamedAccessorsForUsers}; + ObjectAccessor{"address", "address", +std::monostate{}}}, false}; Slice sliceForAddressWithRename = {1, 1, 1, false, +inner}; std::vector renamedAccessorsForUsers = +{sliceForNameWithRename, sliceForAddressWithRename}; ObjectAccessor +accessorUsersWithRename = {"users", "user", renamedAccessorsForUsers}; std::vector rootAccessors3 = { {ObjectAccessor{"id", "id", std::monostate{}}, accessorUsersWithRename}, false}; return rootAccessors3; } -*/ \ No newline at end of file +*/ diff --git a/src/print_filtered_path.cpp b/src/print_filtered_path.cpp index 8f714fd..b21e4b4 100644 --- a/src/print_filtered_path.cpp +++ b/src/print_filtered_path.cpp @@ -1,6 +1,6 @@ #include "print_filtered_path.hpp" -#include "simdjson.h" #include "parse_path.hpp" +#include "simdjson.h" using std::to_string; @@ -10,18 +10,26 @@ void exit_with_error(string message) exit(EXIT_FAILURE); } -#include -#include #include +#include #include +#include void print_value_accessor( growing_string &path, - const ValueAccessor &valueAccessor, simdjson::ondemand::value element, const unsigned flags, vector &filters); + const ValueAccessor &valueAccessor, + simdjson::ondemand::value element, + const unsigned flags, + vector &filters +); void print_slice( growing_string &path, - const Slice &slice, simdjson::ondemand::value element, const unsigned flags, vector &filters) + const Slice &slice, + simdjson::ondemand::value element, + const unsigned flags, + vector &filters +) { int start = slice.start; int end = slice.end; @@ -45,12 +53,15 @@ void print_slice( int path_size = path.size(); for (auto child : array) { - if (index >= start && (index < end) && (slice.step == 1 || (index - start) % slice.step == 0)) + if (index >= start && (index < end) && + (slice.step == 1 || (index - start) % slice.step == 0)) { path.append("["); path.append(std::to_string(index)); path.append("]"); - print_value_accessor(path, slice.value_accessor, child.value(), flags, filters); + print_value_accessor( + path, slice.value_accessor, child.value(), flags, filters + ); path.erase(path_size); } index++; @@ -58,13 +69,19 @@ void print_slice( } else { - exit_with_error("Element is not an array or object at path " + string(path)); + exit_with_error( + "Element is not an array or object at path " + string(path) + ); } } void print_object_accessors( growing_string &path, - const ObjectAccessors &objectAccessors, simdjson::ondemand::value element, const unsigned flags, vector &filters) + const ObjectAccessors &objectAccessors, + simdjson::ondemand::value element, + const unsigned flags, + vector &filters +) { int path_size = path.size(); if (element.type() == simdjson::ondemand::json_type::object) @@ -80,7 +97,8 @@ void print_object_accessors( if (objectAccessor.key == key) { foundMatch = true; - string key_to_use = objectAccessor.new_key.value_or(objectAccessor.key); + string key_to_use = + objectAccessor.new_key.value_or(objectAccessor.key); if (is_js_identifier(key_to_use)) { @@ -94,7 +112,10 @@ void print_object_accessors( path.append("\"]"); } - print_value_accessor(path, objectAccessor.value_accessor, field.value(), flags, filters); + print_value_accessor( + path, objectAccessor.value_accessor, field.value(), + flags, filters + ); path.erase(path_size); @@ -116,7 +137,9 @@ void print_object_accessors( path.append("\"]"); } - recursive_print_gron(field.value(), path, batched_out, flags, filters); + recursive_print_gron( + field.value(), path, batched_out, flags, filters + ); path.erase(path_size); } @@ -130,7 +153,11 @@ void print_object_accessors( void print_all_accessor( growing_string &path, - const AllAccessor &allAccessor, simdjson::ondemand::value element, const unsigned flags, vector &filters) + const AllAccessor &allAccessor, + simdjson::ondemand::value element, + const unsigned flags, + vector &filters +) { if (element.type() == simdjson::ondemand::json_type::array) { @@ -142,7 +169,9 @@ void print_all_accessor( path.append("["); path.append(std::to_string(index++)); path.append("]"); - print_value_accessor(path, allAccessor.value_accessor, child.value(), flags, filters); + print_value_accessor( + path, allAccessor.value_accessor, child.value(), flags, filters + ); path.erase(path_size); } } @@ -166,19 +195,27 @@ void print_all_accessor( path.append("\"]"); } - print_value_accessor(path, allAccessor.value_accessor, field.value(), flags, filters); + print_value_accessor( + path, allAccessor.value_accessor, field.value(), flags, filters + ); path.erase(path_size); } } else { - exit_with_error("Element is not an array or object at path " + string(path)); + exit_with_error( + "Element is not an array or object at path " + string(path) + ); } } void print_value_accessor( growing_string &path, - const ValueAccessor &valueAccessor, simdjson::ondemand::value element, const unsigned flags, vector &filters) + const ValueAccessor &valueAccessor, + simdjson::ondemand::value element, + const unsigned flags, + vector &filters +) { if (std::holds_alternative(valueAccessor)) { @@ -191,16 +228,23 @@ void print_value_accessor( const auto &slicePtr = std::get>(valueAccessor); print_slice(path, *slicePtr, element, flags, filters); } - else if (std::holds_alternative>(valueAccessor)) + else if (std::holds_alternative>( + valueAccessor + )) { // Value accessor is a set of object accessors, handle it - const auto &objectAccessorsPtr = std::get>(valueAccessor); - print_object_accessors(path, *objectAccessorsPtr, element, flags, filters); + const auto &objectAccessorsPtr = + std::get>(valueAccessor); + print_object_accessors( + path, *objectAccessorsPtr, element, flags, filters + ); } - else if (std::holds_alternative>(valueAccessor)) + else if (std::holds_alternative>(valueAccessor + )) { // Value accessor is an all accessor, handle it - const auto &allAccessorPtr = std::get>(valueAccessor); + const auto &allAccessorPtr = + std::get>(valueAccessor); print_all_accessor(path, *allAccessorPtr, element, flags, filters); } else @@ -209,7 +253,13 @@ void print_value_accessor( } } -void print_filtered_path(growing_string &path, int processed, simdjson::ondemand::value element, const unsigned flags, vector &filters) +void print_filtered_path( + growing_string &path, + int processed, + simdjson::ondemand::value element, + const unsigned flags, + vector &filters +) { string_view input = path.view().substr(processed); ValueAccessor valueAccessor = parse_path(input); diff --git a/src/print_filtered_path.hpp b/src/print_filtered_path.hpp index 126b28c..738e74b 100644 --- a/src/print_filtered_path.hpp +++ b/src/print_filtered_path.hpp @@ -1,9 +1,14 @@ #pragma once -#include "simdjson.h" +#include "batched_print.hpp" #include "growing_string.hpp" #include "jsonutils.hpp" #include "print_gron.hpp" -#include "batched_print.hpp" +#include "simdjson.h" -void print_filtered_path(growing_string &path, int processed, simdjson::ondemand::value element, - const unsigned flags, vector &filters); +void print_filtered_path( + growing_string &path, + int processed, + simdjson::ondemand::value element, + const unsigned flags, + vector &filters +); diff --git a/src/print_gron.cpp b/src/print_gron.cpp index 5599342..660c6bb 100644 --- a/src/print_gron.cpp +++ b/src/print_gron.cpp @@ -16,8 +16,13 @@ inline char *print_equals(char *ptr, const unsigned flags) return ptr; } -void recursive_print_gron(simdjson::ondemand::value element, growing_string &path, growing_string &out_growing_string, - const unsigned flags, vector &filters) +void recursive_print_gron( + simdjson::ondemand::value element, + growing_string &path, + growing_string &out_growing_string, + const unsigned flags, + vector &filters +) { switch (element.type()) { @@ -57,7 +62,9 @@ void recursive_print_gron(simdjson::ondemand::value element, growing_string &pat path.append("\033[1;34m]\033[0m"); else path.append("]"); - recursive_print_gron(child.value(), path, out_growing_string, flags, filters); + recursive_print_gron( + child.value(), path, out_growing_string, flags, filters + ); path.erase(base_len); } path.erase(orig_base_len); @@ -82,7 +89,8 @@ void recursive_print_gron(simdjson::ondemand::value element, growing_string &pat path.append('\n'); gprint(path, out_growing_string, flags, filters); path.erase(base_len); - // fastgron can directly stream results to out_growing_string if we don't need to sort the output + // fastgron can directly stream results to out_growing_string if we + // don't need to sort the output if (flags & SORT_OUTPUT) { std::vector> fields; @@ -91,7 +99,9 @@ void recursive_print_gron(simdjson::ondemand::value element, growing_string &pat { auto key_orig = field.key(); auto key_value_raw = key_orig.value().raw(); - auto key = string_view(key_value_raw, raw_json_string_length(key_value_raw)); + auto key = string_view( + key_value_raw, raw_json_string_length(key_value_raw) + ); string key_str(key); if (!is_js_identifier(key)) @@ -121,8 +131,10 @@ void recursive_print_gron(simdjson::ondemand::value element, growing_string &pat fields.emplace_back(key_str, string(out2)); out2.erase(0); } - std::sort(fields.begin(), fields.end(), [](auto &a, auto &b) - { return a.first < b.first; }); + std::sort( + fields.begin(), fields.end(), + [](auto &a, auto &b) { return a.first < b.first; } + ); for (auto &field : fields) { out_growing_string.append(field.second); @@ -135,7 +147,9 @@ void recursive_print_gron(simdjson::ondemand::value element, growing_string &pat { auto key_orig = field.key(); auto key_value_raw = key_orig.value().raw(); - auto key = string_view(key_value_raw, raw_json_string_length(key_value_raw)); + auto key = string_view( + key_value_raw, raw_json_string_length(key_value_raw) + ); if (!is_js_identifier(key)) { if (flags & COLOR) @@ -157,7 +171,9 @@ void recursive_print_gron(simdjson::ondemand::value element, growing_string &pat if (flags & COLOR) path.append("\033[0m"); } - recursive_print_gron(field.value(), path, out_growing_string, flags, filters); + recursive_print_gron( + field.value(), path, out_growing_string, flags, filters + ); path.erase(base_len); } } @@ -171,7 +187,9 @@ void recursive_print_gron(simdjson::ondemand::value element, growing_string &pat size_t orig_out_len = out_growing_string.size(); size_t path_size = path.size(); string_view s = element.raw_json_token(); - out_growing_string.reserve_extra(path_size + orig_out_len + s.length() + 30); + out_growing_string.reserve_extra( + path_size + orig_out_len + s.length() + 30 + ); char *ptr = &out_growing_string.data[orig_out_len]; memcpy(ptr, path.data, path_size); ptr += path_size; @@ -201,8 +219,9 @@ void recursive_print_gron(simdjson::ondemand::value element, growing_string &pat } *ptr++ = 'm'; } - while (s.size() > 0 && (s[s.size() - 1] == ' ' || s[s.size() - 1] == '\n' || - s[s.size() - 1] == '\r' || s[s.size() - 1] == '\t')) + while (s.size() > 0 && + (s[s.size() - 1] == ' ' || s[s.size() - 1] == '\n' || + s[s.size() - 1] == '\r' || s[s.size() - 1] == '\t')) { s.remove_suffix(1); } @@ -220,7 +239,10 @@ void recursive_print_gron(simdjson::ondemand::value element, growing_string &pat *ptr++ = ';'; } *ptr++ = '\n'; - string_view ss = string_view(&out_growing_string.data[orig_out_len], ptr - &out_growing_string.data[orig_out_len]); + string_view ss = string_view( + &out_growing_string.data[orig_out_len], + ptr - &out_growing_string.data[orig_out_len] + ); if (can_show(ss, flags, filters)) { if (flags & COLORIZE_MATCHES) diff --git a/src/print_gron.hpp b/src/print_gron.hpp index d31fbe7..ff40f3b 100644 --- a/src/print_gron.hpp +++ b/src/print_gron.hpp @@ -1,19 +1,24 @@ #pragma once -#include "simdjson.h" -#include "jsonutils.hpp" -#include "growing_string.hpp" #include "batched_print.hpp" +#include "growing_string.hpp" +#include "jsonutils.hpp" +#include "simdjson.h" #include -#include #include #include +#include using simdjson::ondemand::value; using std::string; using std::string_view; using std::vector; -void recursive_print_gron(simdjson::ondemand::value element, growing_string &path, growing_string &out_growing_string, - const unsigned flags, vector &filters); +void recursive_print_gron( + simdjson::ondemand::value element, + growing_string &path, + growing_string &out_growing_string, + const unsigned flags, + vector &filters +); inline growing_string &colorize_matches(string_view s, vector &filters) { @@ -47,7 +52,12 @@ inline growing_string &colorize_matches(string_view s, vector &filters) return out; } -inline void gprint(string_view s, growing_string &out_growing_string, const unsigned flags, vector &filters) +inline void gprint( + string_view s, + growing_string &out_growing_string, + const unsigned flags, + vector &filters +) { if (!can_show(s, flags, filters)) { diff --git a/src/print_json.cpp b/src/print_json.cpp index bf8366d..3e72d77 100644 --- a/src/print_json.cpp +++ b/src/print_json.cpp @@ -2,9 +2,13 @@ #include "batched_print.hpp" #include "jsonutils.hpp" -void print_json_inner(Builder& builder, const unsigned flags, growing_string &indent); +void print_json_inner( + Builder &builder, const unsigned flags, growing_string &indent +); -void print_vector(Vector &vector_holder, const unsigned flags, growing_string &indent) +void print_vector( + Vector &vector_holder, const unsigned flags, growing_string &indent +) { batched_out.append('['); if (flags & NEWLINE) @@ -80,7 +84,9 @@ void print_map(Map &map_holder, const unsigned flags, growing_string &indent) batched_print("}"); } -void print_json_inner(Builder& builder, const unsigned flags, growing_string &indent) +void print_json_inner( + Builder &builder, const unsigned flags, growing_string &indent +) { if (std::holds_alternative(builder)) { @@ -102,7 +108,7 @@ void print_json_inner(Builder& builder, const unsigned flags, growing_string &in } } -void print_json(Builder& builder, const unsigned flags) +void print_json(Builder &builder, const unsigned flags) { growing_string indent; batched_out.reserve_extra(1000000); diff --git a/src/print_json.hpp b/src/print_json.hpp index 9b1bee8..c3aec7f 100644 --- a/src/print_json.hpp +++ b/src/print_json.hpp @@ -1,4 +1,4 @@ #pragma once #include "builder.hpp" -void print_json(Builder& builder, const unsigned flags); +void print_json(Builder &builder, const unsigned flags); diff --git a/src/test.json b/src/test.json index a307b1a..f6e11dc 100644 --- a/src/test.json +++ b/src/test.json @@ -1,5 +1,5 @@ { - "asdf": 3, - "sdfsdf": 4 + "asdf": 3, + "sdfsdf": 4 } \ No newline at end of file diff --git a/test2.json b/test2.json index fa60039..9e5938e 100644 --- a/test2.json +++ b/test2.json @@ -1,4 +1,4 @@ { - "a": 2, - "b": 3 - } \ No newline at end of file + "a": 2, + "b": 3 +} \ No newline at end of file From 8500c976c65d9325d99b1224c3c26c29627c671a Mon Sep 17 00:00:00 2001 From: Joseph LaFreniere Date: Sat, 6 Jan 2024 09:06:43 -0600 Subject: [PATCH 3/3] Add GitHub Actions workflow to run `nix flake check` --- .github/workflows/ci.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1580535 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,17 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/github-workflow.json +--- +name: Continuous Integration + +on: + pull_request: + branches: + - main + workflow_dispatch: {} + +jobs: + nix-flake-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: cachix/install-nix-action@v24 + - run: nix flake check --show-trace