Remove const char* variants for at_key()

- Remove const char * variants for at_key(), string_view covers them
- Add at_key_case_insensitive variants on *_result
- Add at(), at_key(), at_key_case_insensitive() tests
This commit is contained in:
John Keiser 2020-03-27 09:09:08 -07:00
parent f0f111b387
commit c14b2fb36c
3 changed files with 90 additions and 169 deletions

View File

@ -180,6 +180,20 @@ public:
*/
inline element_result at_key(std::string_view s) const noexcept;
/**
* Get the value associated with the given key.
*
* Note: The key will be matched against **unescaped** JSON:
*
* document::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(const char *s) const noexcept;
std::unique_ptr<uint64_t[]> tape;
std::unique_ptr<uint8_t[]> string_buf;// should be at least byte_capacity
@ -635,14 +649,18 @@ public:
inline element_result at_key(std::string_view s) const noexcept;
/**
* Get the value associated with the given key in a case-insensitive manner.
* Get the value associated with the given key.
*
* Note: The key will be matched against **unescaped** JSON.
* Note: The key will be matched against **unescaped** JSON:
*
* document::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key_case_insensitive(std::string_view s) const noexcept;
inline element_result at_key(const char *s) const noexcept;
private:
really_inline element(const document *_doc, size_t _json_index) noexcept;
@ -876,7 +894,7 @@ public:
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(std::string_view key) const noexcept;
inline element_result at_key(std::string_view s) const noexcept;
/**
* Get the value associated with the given key.
@ -886,8 +904,18 @@ public:
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(const char *key) const noexcept;
inline element_result at_key(const char *s) const noexcept;
/**
* Get the value associated with the given key, the provided key is
* considered to have length characters.
*
* Note: The key will be matched against **unescaped** JSON.
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(const char *s, size_t length) const noexcept;
/**
* Get the value associated with the given key in a case-insensitive manner.
*
@ -896,17 +924,7 @@ public:
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key_case_insensitive(std::string_view key) const noexcept;
/**
* Get the value associated with the given key in a case-insensitive manner.
*
* Note: The key will be matched against **unescaped** JSON.
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key_case_insensitive(const char *key) const noexcept;
inline element_result at_key_case_insensitive(const char *s) const noexcept;
private:
really_inline object(const document *_doc, size_t _json_index) noexcept;
@ -954,8 +972,6 @@ public:
inline element_result at(size_t index) const noexcept;
inline element_result at_key(std::string_view key) const noexcept;
inline element_result at_key(const char *key) const noexcept;
inline element_result at_key_case_insensitive(std::string_view key) const noexcept;
inline element_result at_key_case_insensitive(const char *key) const noexcept;
#if SIMDJSON_EXCEPTIONS
inline operator bool() const noexcept(false);
@ -998,7 +1014,7 @@ public:
inline element_result operator[](const char *json_pointer) const noexcept;
inline element_result at(std::string_view json_pointer) const noexcept;
inline element_result at_key(std::string_view key) const noexcept;
inline element_result at_key_case_insensitive(std::string_view key) const noexcept;
inline element_result at_key(const char *key) const noexcept;
#if SIMDJSON_EXCEPTIONS
inline object::iterator begin() const noexcept(false);

View File

@ -75,9 +75,9 @@ inline document::element_result document::element_result::at_key(std::string_vie
if (error()) { return *this; }
return first.at_key(key);
}
inline document::element_result document::element_result::at_key_case_insensitive(std::string_view key) const noexcept {
inline document::element_result document::element_result::at_key(const char *key) const noexcept {
if (error()) { return *this; }
return first.at_key_case_insensitive(key);
return first.at_key(key);
}
#if SIMDJSON_EXCEPTIONS
@ -167,9 +167,9 @@ inline document::element_result document::object_result::at_key(std::string_view
if (error()) { return error(); }
return first.at_key(key);
}
inline document::element_result document::object_result::at_key_case_insensitive(std::string_view key) const noexcept {
inline document::element_result document::object_result::at_key(const char *key) const noexcept {
if (error()) { return error(); }
return first.at_key_case_insensitive(key);
return first.at_key(key);
}
#if SIMDJSON_EXCEPTIONS
@ -227,6 +227,9 @@ inline document::element_result document::at(size_t index) const noexcept {
inline document::element_result document::at_key(std::string_view key) const noexcept {
return as_object().at_key(key);
}
inline document::element_result document::at_key(const char *key) const noexcept {
return as_object().at_key(key);
}
inline document::element_result document::operator[](std::string_view json_pointer) const noexcept {
return at(json_pointer);
}
@ -782,6 +785,16 @@ inline document::element_result document::object::at(std::string_view json_point
return child;
}
inline document::element_result document::object::at_key(const char *key, size_t length) const noexcept {
iterator end_field = end();
for (iterator field = begin(); field != end_field; ++field) {
std::string_view v{field.key()};
if ((v.size() == length) && (!memcmp(v.data(), key, length))) {
return field.value();
}
}
return NO_SUCH_FIELD;
}
inline document::element_result document::object::at_key(std::string_view key) const noexcept {
iterator end_field = end();
for (iterator field = begin(); field != end_field; ++field) {
@ -791,21 +804,27 @@ inline document::element_result document::object::at_key(std::string_view key) c
}
return NO_SUCH_FIELD;
}
// In case you wonder why we need this, please see
// https://github.com/simdjson/simdjson/issues/323
// People do seek keys in a case-insensitive manner.
inline document::element_result document::object::at_key_case_insensitive(std::string_view key) const noexcept {
inline document::element_result document::object::at_key(const char *key) const noexcept {
iterator end_field = end();
for (iterator field = begin(); field != end_field; ++field) {
if (std::equal(key.begin(), key.end(), field.key().begin(), [](char a, char b) {
return std::tolower(a) == std::tolower(b);
})) {
if (!strcmp(key, field.key_c_str())) {
return field.value();
}
}
return NO_SUCH_FIELD;
}
// In case you wonder why we need this, please see
// https://github.com/simdjson/simdjson/issues/323
// People do seek keys in a case-insensitive manner.
inline document::element_result document::object::at_key_case_insensitive(const char *key) const noexcept {
iterator end_field = end();
for (iterator field = begin(); field != end_field; ++field) {
if (!simdjson_strcasecmp(key, field.key_c_str())) {
return field.value();
}
}
return NO_SUCH_FIELD;
}
//
// document::object::iterator inline implementation
//
@ -1004,8 +1023,8 @@ inline document::element_result document::element::at(size_t index) const noexce
inline document::element_result document::element::at_key(std::string_view key) const noexcept {
return as_object().at_key(key);
}
inline document::element_result document::element::at_key_case_insensitive(std::string_view key) const noexcept {
return as_object().at_key_case_insensitive(key);
inline document::element_result document::element::at_key(const char *key) const noexcept {
return as_object().at_key(key);
}
//

View File

@ -567,7 +567,7 @@ namespace parse_api_tests {
}
}
namespace deprecated_tests {
namespace dom_api_tests {
using namespace std;
using namespace simdjson;
@ -674,22 +674,11 @@ namespace deprecated_tests {
}
return true;
}
SIMDJSON_POP_DISABLE_WARNINGS
bool run() {
return ParsedJson_Iterator_test() &&
true;
}
}
namespace dom_api_tests {
using namespace std;
using namespace simdjson;
bool object_iterator() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"({ "a": 1, "b": 2, "c": 3 })"_padded;
string json(R"({ "a": 1, "b": 2, "c": 3 })");
const char* expected_key[] = { "a", "b", "c" };
uint64_t expected_value[] = { 1, 2, 3 };
int i = 0;
@ -707,7 +696,7 @@ namespace dom_api_tests {
bool array_iterator() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([ 1, 10, 100 ])"_padded;
string json(R"([ 1, 10, 100 ])");
uint64_t expected_value[] = { 1, 10, 100 };
int i=0;
@ -724,7 +713,7 @@ namespace dom_api_tests {
bool object_iterator_empty() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"({})"_padded;
string json(R"({})");
int i = 0;
document::parser parser;
@ -740,7 +729,7 @@ namespace dom_api_tests {
bool array_iterator_empty() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([])"_padded;
string json(R"([])");
int i=0;
document::parser parser;
@ -754,108 +743,9 @@ namespace dom_api_tests {
return true;
}
bool array_at() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([ 1, 10, 100 ])"_padded;
uint64_t expected[] = { 1, 10, 100 };
document::parser parser;
auto [array, error] = parser.parse(json).as_array();
uint64_t actual;
{
int i = 2;
array.at(i).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected[i]) { cerr << "Got [" << i << "] = " << actual << ", expected " << expected[i] << endl; return false; }
}
{
int i = 0;
array.at(i).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected[i]) { cerr << "Got [" << i << "] = " << actual << ", expected " << expected[i] << endl; return false; }
}
{
int i = 1;
array.at(i).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected[i]) { cerr << "Got [" << i << "] = " << actual << ", expected " << expected[i] << endl; return false; }
}
{
int i = 3;
array.at(i).as_uint64_t().tie(actual, error);
if (!error) { cerr << "Expected error accessing [" << i << "], got " << actual << " instead!" << endl; return false; }
}
return true;
}
bool object_at_key() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"({ "foo": 1, "bar": 2 })"_padded;
document::parser parser;
auto [object, error] = parser.parse(json).as_object();
uint64_t actual;
{
string key = "bar";
uint64_t expected = 2;
object.at_key(key).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected) { cerr << "Got " << key << " = " << actual << ", expected " << expected << endl; return false; }
}
{
string key = "foo";
uint64_t expected = 1;
object.at_key(key).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected) { cerr << "Got " << key << " = " << actual << ", expected " << expected << endl; return false; }
}
{
string key = "baz";
object.at_key(key).as_uint64_t().tie(actual, error);
if (!error) { cerr << "Expected error accessing " << key << ", got " << actual << " instead!" << endl; return false; }
}
return true;
}
bool object_at_key_case_insensitive() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"({ "foo": 1, "Bar": 2 })"_padded;
document::parser parser;
auto [object, error] = parser.parse(json).as_object();
uint64_t actual;
{
string key = "bar";
uint64_t expected = 2;
object.at_key_case_insensitive(key).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected) { cerr << "Got " << key << " = " << actual << ", expected " << expected << endl; return false; }
}
{
string key = "BAR";
uint64_t expected = 2;
object.at_key_case_insensitive(key).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected) { cerr << "Got " << key << " = " << actual << ", expected " << expected << endl; return false; }
}
{
string key = "Bar";
uint64_t expected = 2;
object.at_key_case_insensitive(key).as_uint64_t().tie(actual, error);
if (error) { cerr << error << endl; return false; }
if (actual != expected) { cerr << "Got " << key << " = " << actual << ", expected " << expected << endl; return false; }
}
{
string key = "baz";
object.at_key_case_insensitive(key).as_uint64_t().tie(actual, error);
if (!error) { cerr << "Expected error accessing " << key << ", got " << actual << " instead!" << endl; return false; }
}
return true;
}
bool string_value() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([ "hi", "has backslash\\" ])"_padded;
string json(R"([ "hi", "has backslash\\" ])");
document::parser parser;
auto [array, error] = parser.parse(json).as_array();
if (error) { cerr << "Error: " << error << endl; return false; }
@ -869,7 +759,7 @@ namespace dom_api_tests {
bool numeric_values() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([ 0, 1, -1, 1.1 ])"_padded;
string json(R"([ 0, 1, -1, 1.1 ])");
document::parser parser;
auto [array, error] = parser.parse(json).as_array();
if (error) { cerr << "Error: " << error << endl; return false; }
@ -892,7 +782,7 @@ namespace dom_api_tests {
bool boolean_values() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([ true, false ])"_padded;
string json(R"([ true, false ])");
document::parser parser;
auto [array, error] = parser.parse(json).as_array();
if (error) { cerr << "Error: " << error << endl; return false; }
@ -906,7 +796,7 @@ namespace dom_api_tests {
bool null_value() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([ null ])"_padded;
string json(R"([ null ])");
document::parser parser;
auto [array, error] = parser.parse(json).as_array();
if (error) { cerr << "Error: " << error << endl; return false; }
@ -917,7 +807,7 @@ namespace dom_api_tests {
bool document_object_index() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"({ "a": 1, "b": 2, "c": 3})"_padded;
string json(R"({ "a": 1, "b": 2, "c": 3})");
document::parser parser;
auto [doc, error] = parser.parse(json);
if (doc["a"].as_uint64_t().first != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << doc["a"].first << endl; return false; }
@ -937,7 +827,7 @@ namespace dom_api_tests {
bool object_index() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"({ "obj": { "a": 1, "b": 2, "c": 3 } })"_padded;
string json(R"({ "obj": { "a": 1, "b": 2, "c": 3 } })");
document::parser parser;
auto [doc, error] = parser.parse(json);
if (error) { cerr << "Error: " << error << endl; return false; }
@ -1031,7 +921,7 @@ namespace dom_api_tests {
bool object_iterator_exception() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"({ "a": 1, "b": 2, "c": 3 })"_padded;
string json(R"({ "a": 1, "b": 2, "c": 3 })");
const char* expected_key[] = { "a", "b", "c" };
uint64_t expected_value[] = { 1, 2, 3 };
int i = 0;
@ -1048,7 +938,7 @@ namespace dom_api_tests {
bool array_iterator_exception() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([ 1, 10, 100 ])"_padded;
string json(R"([ 1, 10, 100 ])");
uint64_t expected_value[] = { 1, 10, 100 };
int i=0;
@ -1064,7 +954,7 @@ namespace dom_api_tests {
bool string_value_exception() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([ "hi", "has backslash\\" ])"_padded;
string json(R"([ "hi", "has backslash\\" ])");
document::parser parser;
document::array array = parser.parse(json).as_array();
auto val = array.begin();
@ -1079,7 +969,7 @@ namespace dom_api_tests {
bool numeric_values_exception() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([ 0, 1, -1, 1.1 ])"_padded;
string json(R"([ 0, 1, -1, 1.1 ])");
document::parser parser;
document::array array = parser.parse(json).as_array();
auto val = array.begin();
@ -1101,7 +991,7 @@ namespace dom_api_tests {
bool boolean_values_exception() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([ true, false ])"_padded;
string json(R"([ true, false ])");
document::parser parser;
document::array array = parser.parse(json).as_array();
auto val = array.begin();
@ -1114,7 +1004,7 @@ namespace dom_api_tests {
bool null_value_exception() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"([ null ])"_padded;
string json(R"([ null ])");
document::parser parser;
document::array array = parser.parse(json).as_array();
auto val = array.begin();
@ -1125,7 +1015,7 @@ namespace dom_api_tests {
bool document_object_index_exception() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"({ "a": 1, "b": 2, "c": 3})"_padded;
string json(R"({ "a": 1, "b": 2, "c": 3})");
document::parser parser;
document &doc = parser.parse(json);
if (uint64_t(doc["a"]) != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << uint64_t(doc["a"]) << endl; return false; }
@ -1134,7 +1024,7 @@ namespace dom_api_tests {
bool object_index_exception() {
std::cout << "Running " << __func__ << std::endl;
auto json = R"({ "obj": { "a": 1, "b": 2, "c": 3 } })"_padded;
string json(R"({ "obj": { "a": 1, "b": 2, "c": 3 } })");
document::parser parser;
document::object obj = parser.parse(json)["obj"];
if (uint64_t(obj["a"]) != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << uint64_t(obj["a"]) << endl; return false; }
@ -1190,13 +1080,11 @@ namespace dom_api_tests {
#endif
bool run() {
return object_iterator() &&
return ParsedJson_Iterator_test() &&
object_iterator() &&
array_iterator() &&
object_iterator_empty() &&
array_iterator_empty() &&
array_at() &&
object_at_key() &&
object_at_key_case_insensitive() &&
string_value() &&
numeric_values() &&
boolean_values() &&
@ -1506,10 +1394,8 @@ int main(int argc, char *argv[]) {
format_tests::run() &&
document_tests::run() &&
number_tests::run() &&
error_messages_in_correct_order() &&
deprecated_tests::run() &&
document_stream_tests::run() &&
true
error_messages_in_correct_order()
) {
std::cout << "Basic tests are ok." << std::endl;
return EXIT_SUCCESS;