From 63ee2126b26f8d6596e4e0e711e92aa3eff567f0 Mon Sep 17 00:00:00 2001 From: stefanocasazza Date: Tue, 19 Mar 2019 15:21:10 +0100 Subject: [PATCH] sync --- include/ulib/base/utility.h | 28 +++++++++ include/ulib/json/value.h | 11 ++++ include/ulib/string.h | 38 +++++++++++- include/ulib/tokenizer.h | 22 +++++++ src/ulib/json/value.cpp | 116 +++++++++++++++++++++++++++++++++++ src/ulib/string.cpp | 47 +++++--------- tests/examples/TSA/tsaserial | 2 +- tests/ulib/test_json.cpp | 20 +++++- 8 files changed, 245 insertions(+), 39 deletions(-) diff --git a/include/ulib/base/utility.h b/include/ulib/base/utility.h index f13a2b3d..ad2b4008 100644 --- a/include/ulib/base/utility.h +++ b/include/ulib/base/utility.h @@ -767,6 +767,34 @@ static inline unsigned long u_atoi(const char* restrict s) #endif } +static inline bool u_trim(const char** restrict s, uint32_t* n) +{ + // skip white space from start + + uint32_t _length = *n; + const char* restrict str = *s; + + while (_length && u__isspace(*str)) + { + ++str; + --_length; + } + + // skip white space from end + + while (_length && u__isspace(str[_length-1])) --_length; + + if (_length != *n) + { + *n = _length; + *s = str; + + return true; + } + + return false; +} + U_EXPORT int8_t u_log2(uint64_t value) __pure; static inline unsigned u__octc2int(unsigned char c) { return ((c - '0') & 07); } diff --git a/include/ulib/json/value.h b/include/ulib/json/value.h index ff4911b5..47af573d 100644 --- a/include/ulib/json/value.h +++ b/include/ulib/json/value.h @@ -18,6 +18,10 @@ #include +#if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX17) +# include +#endif + /** * \brief Represents a JSON value. * @@ -593,6 +597,12 @@ public: static int jreadArrayStep(const UString& jarray, UString& result); // assumes jarray points at the start of an array or array element + // by Victor Stewart + +#if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX17) + static void consumeFieldsAndValues(const UString& json, std::function consumer); // assumes perfect construction +#endif + #ifdef DEBUG const char* dump(bool _reset) const; @@ -1063,6 +1073,7 @@ protected: private: static int jread_skip(UTokenizer& tok) U_NO_EXPORT; static int jreadFindToken(UTokenizer& tok) U_NO_EXPORT; + static int jreadAdvanceAndFindToken(UTokenizer& tok) U_NO_EXPORT; static UString jread_string(UTokenizer& tok) U_NO_EXPORT; static UString jread_object(UTokenizer& tok) U_NO_EXPORT; diff --git a/include/ulib/string.h b/include/ulib/string.h index 54929f6b..b37941ff 100644 --- a/include/ulib/string.h +++ b/include/ulib/string.h @@ -31,7 +31,7 @@ enum StringAllocationType { }; enum StringAllocationIndex { - STR_ALLOCATE_INDEX_SOAP = 20, + STR_ALLOCATE_INDEX_SOAP = 21, STR_ALLOCATE_INDEX_IMAP = STR_ALLOCATE_INDEX_SOAP+14, STR_ALLOCATE_INDEX_SSI = STR_ALLOCATE_INDEX_IMAP+4, STR_ALLOCATE_INDEX_NOCAT = STR_ALLOCATE_INDEX_SSI+2, @@ -810,7 +810,16 @@ public: // for constant string - void trim(); + void trim() + { + U_TRACE_NO_PARAM(0, "UStringRep::trim()") + + U_CHECK_MEMORY + + U_INTERNAL_ASSERT_EQUALS(_capacity, 0) + + (void) u_trim(&str, &_length); + } // if the string is quoted... @@ -1149,6 +1158,7 @@ public: static const UString* str_false; static const UString* str_response; static const UString* str_zero; + static const UString* str_one; static const UString* str_nostat; static const UString* str_tsa; static const UString* str_soap; @@ -1611,6 +1621,30 @@ public: return substr(rep->str + pos, rep->fold(pos, n)); } + UString substrTrim(const char* t, uint32_t tlen) const + { + U_TRACE(0, "UString::substrTrim(%.*S,%u)", tlen, t, tlen) + + if (tlen == 0 || + (u_trim(&t, &tlen) && tlen == 0)) + { + return *string_null; + } + + UString result(rep, t, tlen); + + U_RETURN_STRING(result); + } + + UString substrTrim(uint32_t pos, uint32_t n = U_NOT_FOUND) const + { + U_TRACE(0, "UString::substrTrim(%u,%u)", pos, n) + + U_INTERNAL_ASSERT(pos <= rep->_length) + + return substrTrim(rep->str + pos, rep->fold(pos, n)); + } + bool isSubStringOf(const UString& str) const { return rep->isSubStringOf(str.rep); } // destructor diff --git a/include/ulib/tokenizer.h b/include/ulib/tokenizer.h index 67a5dd51..2dd5cc9c 100644 --- a/include/ulib/tokenizer.h +++ b/include/ulib/tokenizer.h @@ -268,6 +268,28 @@ public: U_RETURN_STRING(result); } + UString substrTrim() const + { + U_TRACE_NO_PARAM(0, "UTokenizer::substrTrim()") + + UString result; + + if (s < end) result = str.substrTrim(str.distance(s)); + + U_RETURN_STRING(result); + } + + UString substrTrim(const char* start) const + { + U_TRACE(0, "UTokenizer::substrTrim(%p)", start) + + UString result; + + if (start < end) result = str.substrTrim(start, s - start); + + U_RETURN_STRING(result); + } + UString getTokenQueryParser(); int getTokenId(UString* ptoken); diff --git a/src/ulib/json/value.cpp b/src/ulib/json/value.cpp index ef267b62..1a1c7fa1 100644 --- a/src/ulib/json/value.cpp +++ b/src/ulib/json/value.cpp @@ -1939,6 +1939,15 @@ U_NO_EXPORT int UValue::jreadFindToken(UTokenizer& tok) U_RETURN(-1); } +U_NO_EXPORT int UValue::jreadAdvanceAndFindToken(UTokenizer& tok) +{ + U_TRACE(0, "UValue::jreadAdvanceAndFindToken(%p)", &tok) + + tok.advance(); + + return jreadFindToken(tok); +} + U_NO_EXPORT int UValue::jread_skip(UTokenizer& tok) { U_TRACE(0, "UValue::jread_skip(%p)", &tok) @@ -2612,6 +2621,113 @@ int UValue::jreadArrayStep(const UString& jarray, UString& result) U_RETURN(jTok); } +// by Victor Stewart + +#if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX17) +void UValue::consumeFieldsAndValues(const UString& json, std::function consumer) // assumes perfect construction +{ + U_TRACE(0, "UValue::consumeFieldsAndValues(%V,%p)", json.rep, &consumer) + + int jTok; + UTokenizer tok(json); + UString field, value; + const char* fieldStart; + const char* valueStart; + + while ((jTok = jreadFindToken(tok)) != U_JR_EOL) + { + U_DUMP("jTok = (%d,%S)", jTok, getDataTypeDescription(jTok)) + + // all fields must be encapsulated by quotations + if (jTok != U_STRING_VALUE) + { + tok.advance(); // aka skip opening bracket and commas + + continue; + } + + fieldStart = tok.getPointer() + 1; + + // find closing quotation + while (jreadAdvanceAndFindToken(tok) != U_STRING_VALUE) {}; + + // capture field name + field = tok.substr(fieldStart); + + // skip til colon + while (jreadAdvanceAndFindToken(tok) != U_JR_COLON) {}; + + // skip past the colon it enters on + + switch (jreadAdvanceAndFindToken(tok)) + { + case U_REAL_VALUE: + { + // skip ahead til either we hit a space or a comma + + valueStart = tok.getPointer(); + + while (jreadAdvanceAndFindToken(tok) != U_REAL_VALUE) {}; + + value = tok.substrTrim(valueStart); // possible space between end of value and comma + } + break; + + case U_TRUE_VALUE: value = *UString::str_one; break; + case U_FALSE_VALUE: value = *UString::str_zero; break; + + case U_STRING_VALUE: + { + valueStart = tok.getPointer() + 1; + + while (jreadAdvanceAndFindToken(tok) != U_STRING_VALUE) {}; + + value = tok.substr(valueStart); + } + break; + + case U_ARRAY_VALUE: + case U_OBJECT_VALUE: + { + int hunting = 1; + + valueStart = tok.getPointer(); + + do { + switch (jreadAdvanceAndFindToken(tok)) + { + case U_REAL_VALUE: + case U_TRUE_VALUE: + case U_FALSE_VALUE: + // case U_NULL_VALUE: + case U_STRING_VALUE: + case U_JR_COLON: + case U_JR_COMMA: + // case U_JR_QPARAM: + break; + case U_JR_EARRAY: + case U_JR_EOBJECT: --hunting; break; + case U_ARRAY_VALUE: + case U_OBJECT_VALUE: ++hunting; break; + } + } + while (hunting > 0); + + // we are on the ending char/boundary of a container + tok.advance(); + value = tok.substr(valueStart); + } + break; + } + + consumer(field, value); + + field.clear(); + value.clear(); + } +} +#endif + // DEBUG #ifdef DEBUG diff --git a/src/ulib/string.cpp b/src/ulib/string.cpp index 08fb43b8..50294b54 100644 --- a/src/ulib/string.cpp +++ b/src/ulib/string.cpp @@ -40,6 +40,7 @@ const UString* UString::str_true; const UString* UString::str_false; const UString* UString::str_response; const UString* UString::str_zero; +const UString* UString::str_one; const UString* UString::str_nostat; const UString* UString::str_tsa; const UString* UString::str_soap; @@ -181,9 +182,9 @@ const UString* UString::str_ULib; #endif #ifdef U_HTTP2_DISABLE -static ustringrep stringrep_storage[74] = { +static ustringrep stringrep_storage[75] = { #else -static ustringrep stringrep_storage[138] = { +static ustringrep stringrep_storage[139] = { #endif { U_STRINGREP_FROM_CONSTANT("host") }, { U_STRINGREP_FROM_CONSTANT("chunked") }, @@ -199,6 +200,7 @@ static ustringrep stringrep_storage[138] = { { U_STRINGREP_FROM_CONSTANT("false") }, { U_STRINGREP_FROM_CONSTANT("response") }, { U_STRINGREP_FROM_CONSTANT("0") }, + { U_STRINGREP_FROM_CONSTANT("1") }, { U_STRINGREP_FROM_CONSTANT("/nostat") }, { U_STRINGREP_FROM_CONSTANT("/tsa") }, { U_STRINGREP_FROM_CONSTANT("/soap") }, @@ -356,6 +358,7 @@ void UString::str_allocate(int which) U_INTERNAL_ASSERT_EQUALS(str_false, U_NULLPTR) U_INTERNAL_ASSERT_EQUALS(str_response, U_NULLPTR) U_INTERNAL_ASSERT_EQUALS(str_zero, U_NULLPTR) + U_INTERNAL_ASSERT_EQUALS(str_one, U_NULLPTR) U_INTERNAL_ASSERT_EQUALS(str_nostat, U_NULLPTR) U_INTERNAL_ASSERT_EQUALS(str_tsa, U_NULLPTR) U_INTERNAL_ASSERT_EQUALS(str_soap, U_NULLPTR) @@ -377,13 +380,14 @@ void UString::str_allocate(int which) U_NEW_ULIB_STRING(str_false, UString(stringrep_storage+11)); U_NEW_ULIB_STRING(str_response, UString(stringrep_storage+12)); U_NEW_ULIB_STRING(str_zero, UString(stringrep_storage+13)); - U_NEW_ULIB_STRING(str_nostat, UString(stringrep_storage+14)); - U_NEW_ULIB_STRING(str_tsa, UString(stringrep_storage+15)); - U_NEW_ULIB_STRING(str_soap, UString(stringrep_storage+16)); - U_NEW_ULIB_STRING(str_path_root, UString(stringrep_storage+17)); - U_NEW_ULIB_STRING(str_asterisk, UString(stringrep_storage+18)); + U_NEW_ULIB_STRING(str_one, UString(stringrep_storage+14)); + U_NEW_ULIB_STRING(str_nostat, UString(stringrep_storage+15)); + U_NEW_ULIB_STRING(str_tsa, UString(stringrep_storage+16)); + U_NEW_ULIB_STRING(str_soap, UString(stringrep_storage+17)); + U_NEW_ULIB_STRING(str_path_root, UString(stringrep_storage+18)); + U_NEW_ULIB_STRING(str_asterisk, UString(stringrep_storage+19)); - uustringrep key1 = { stringrep_storage+19 }; + uustringrep key1 = { stringrep_storage+20 }; pkey = key1.p2; @@ -530,7 +534,7 @@ void UString::str_allocate(int which) else if ((which & STR_ALLOCATE_HTTP2) != 0) { U_INTERNAL_ASSERT_EQUALS(str_authority, U_NULLPTR) - U_INTERNAL_ASSERT_EQUALS(U_NUM_ELEMENTS(stringrep_storage), 138) + U_INTERNAL_ASSERT_EQUALS(U_NUM_ELEMENTS(stringrep_storage), 139) U_NEW_ULIB_STRING(str_authority, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+0)); U_NEW_ULIB_STRING(str_method, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+1)); @@ -598,7 +602,7 @@ void UString::str_allocate(int which) U_NEW_ULIB_STRING(str_ULib, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+63)); } #else - U_INTERNAL_ASSERT_EQUALS(U_NUM_ELEMENTS(stringrep_storage), 74) + U_INTERNAL_ASSERT_EQUALS(U_NUM_ELEMENTS(stringrep_storage), 75) #endif } @@ -1074,29 +1078,6 @@ uint32_t UStringRep::copy(char* s, uint32_t n, uint32_t pos) const U_RETURN(n); } -void UStringRep::trim() -{ - U_TRACE_NO_PARAM(0, "UStringRep::trim()") - - U_CHECK_MEMORY - - U_INTERNAL_ASSERT_EQUALS(_capacity, 0) - - // skip white space from start - - while (_length && u__isspace(*str)) - { - ++str; - --_length; - } - - U_INTERNAL_DUMP("_length = %u", _length) - - // skip white space from end - - while (_length && u__isspace(str[_length-1])) --_length; -} - __pure int UStringRep::compare(const UStringRep* rep, uint32_t depth) const { U_TRACE(0, "UStringRep::compare(%p,%u)", rep, depth) diff --git a/tests/examples/TSA/tsaserial b/tests/examples/TSA/tsaserial index 35669603..7f955446 100644 --- a/tests/examples/TSA/tsaserial +++ b/tests/examples/TSA/tsaserial @@ -1 +1 @@ -04D1 +04EC diff --git a/tests/ulib/test_json.cpp b/tests/ulib/test_json.cpp index 2e98b704..9fac0864 100644 --- a/tests/ulib/test_json.cpp +++ b/tests/ulib/test_json.cpp @@ -138,6 +138,18 @@ U_EXPORT main (int argc, char* argv[], char* env[]) U_TRACE(5, "main(%d)", argc) + UString workingString; + + // by Victor Stewart + +#if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX17) + workingString = U_STRING_FROM_CONSTANT("{\"ABC\":{\"eventKey\":0,\"eventTime\":18212931298},\"XYZ\":{\"eventKey\":1,\"eventTime\":1111131298}}"); + + UValue::consumeFieldsAndValues(workingString, [&] (const UString& field, const UString& value) -> void { + u__printf(STDERR_FILENO, U_CONSTANT_TO_PARAM("field = %V\nvalue = %V\n"), field.rep, value.rep); + }); +#endif + UValue json; UCrono crono; char buffer[4096]; @@ -350,8 +362,8 @@ U_EXPORT main (int argc, char* argv[], char* env[]) int city; double pricePoint; - UString workingString, query(U_STRING_FROM_CONSTANT("{ \"colorShifts\" : { \"H67\" : -1 }, \"name\" : \"Mr. Taka Ramen\", \"category\" : 39, \"grouping\" : 0," - " \"bumpUp\" : false, \"businessID\" : \"B5401\", \"foundationColor\" : 3, \"coordinates\" : [ -73.9888983, 40.7212405 ] }")); + UString query(U_STRING_FROM_CONSTANT("{ \"colorShifts\" : { \"H67\" : -1 }, \"name\" : \"Mr. Taka Ramen\", \"category\" : 39, \"grouping\" : 0," + " \"bumpUp\" : false, \"businessID\" : \"B5401\", \"foundationColor\" : 3, \"coordinates\" : [ -73.9888983, 40.7212405 ] }")); (void) U_JFIND(U_STRING_FROM_CONSTANT("{ \"pricePoint\" : 2.48333333333333, \"socialWeight\" : 8.75832720587083, \"gender\" : 0, \"lessThan16\" : false }"), "pricePoint", pricePoint); @@ -362,6 +374,8 @@ U_EXPORT main (int argc, char* argv[], char* env[]) U_INTERNAL_ASSERT_EQUALS(city, 0) + workingString.clear(); + (void) UValue::jread(query, U_STRING_FROM_CONSTANT("{'coordinates' [0"), workingString); U_INTERNAL_ASSERT_EQUALS(workingString, "-73.9888983") @@ -372,8 +386,8 @@ U_EXPORT main (int argc, char* argv[], char* env[]) U_INTERNAL_ASSERT_EQUALS(workingString, "[ -73.9888983, 40.7212405 ]") + result1.clear(); workingString.clear(); - result1.clear(); (void) U_JFIND(U_STRING_FROM_CONSTANT("{\"saltedHash\":\"f66113b5ed33f961219c\",\"osVersion\":\"10.3.1\",\"socials\":[{\"name\":\"victor]},\"t\":\"createAccount\"}"), "t", result1);