From 2eb67362273df726d585588ec5482afe850c676d Mon Sep 17 00:00:00 2001 From: stefanocasazza Date: Thu, 30 Nov 2017 16:54:08 +0100 Subject: [PATCH] FlatBuffer implementation --- Makefile.am | 2 +- Makefile.in | 2 +- README.md | 3 +- configure | 6 +- configure.ac | 2 +- doc/Doxyfile | 2 +- doc/style.css | 396 +++ include/Makefile.am | 1 + include/Makefile.in | 1 + include/ulib/all.h | 1 + include/ulib/base/macro.h | 9 + include/ulib/base/utility.h | 8 +- include/ulib/container/hash_map.h | 12 +- include/ulib/container/vector.h | 2 + include/ulib/internal/memory_pool.h | 4 - include/ulib/json/value.h | 609 ++-- include/ulib/serialize/flatbuffers.h | 3112 ++++++++++++++++++++ include/ulib/string.h | 17 +- include/ulib/utility/hexdump.h | 4 + include/ulib/utility/string_ext.h | 3 + ltmain.sh | 6 +- m4/ax_lib_postgresql.m4 | 2 +- src/ulib/Makefile.am | 2 +- src/ulib/Makefile.in | 119 +- src/ulib/all_cpp.cpp | 1 + src/ulib/base/base.c | 7 +- src/ulib/internal/common.cpp | 8 +- src/ulib/json/value.cpp | 482 ++- src/ulib/net/server/plugin/mod_proxy.cpp | 12 +- src/ulib/net/server/plugin/php/mod_php.cpp | 20 + src/ulib/net/server/plugin/usp/docalc1.usp | 17 + src/ulib/serialize/flatbuffers.cpp | 364 +++ src/ulib/string.cpp | 9 +- src/ulib/utility/string_ext.cpp | 137 +- src/ulib/utility/uhttp.cpp | 41 +- src/ulib/utility/websocket.cpp | 28 +- tests/examples/web_server.sh | 4 +- tests/ulib/Makefile.am | 9 +- tests/ulib/Makefile.in | 69 +- tests/ulib/json_obj.h | 1548 ++++++++++ tests/ulib/ok/serialize.ok | 0 tests/ulib/serialize.test | 19 + tests/ulib/string.test | 2 +- tests/ulib/test_elasticsearch.cpp | 4 +- tests/ulib/test_json.cpp | 992 +------ tests/ulib/test_memory_pool.cpp | 1 - tests/ulib/test_serialize.cpp | 848 ++++++ tests/ulib/test_string.cpp | 41 +- 48 files changed, 7503 insertions(+), 1485 deletions(-) create mode 100644 doc/style.css create mode 100644 include/ulib/serialize/flatbuffers.h create mode 100644 src/ulib/net/server/plugin/usp/docalc1.usp create mode 100644 src/ulib/serialize/flatbuffers.cpp create mode 100644 tests/ulib/json_obj.h create mode 100644 tests/ulib/ok/serialize.ok create mode 100755 tests/ulib/serialize.test create mode 100644 tests/ulib/test_serialize.cpp diff --git a/Makefile.am b/Makefile.am index f1732602..239faffa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,7 @@ configfiles = userver.service EXTRA_DIST = $(configfiles:%=%.in) \ cdb configure.help TODO LICENSE* README* *.spec* \ - doc/Doxyfile doc/readme.txt shtool *.awk .travis.yml autogen.sh nativejson-benchmark \ + doc/Doxyfile doc/readme.txt doc/style.css shtool *.awk .travis.yml autogen.sh nativejson-benchmark \ ULib.m4 rpm.sh rpmpkgreq.lst rpmpkgreq.lst.suse openwrt CODE_OF_CONDUCT.md CONTRIBUTING.md \ fuzz/http1-corpus fuzz/http2-corpus fuzz/build_libFuzzer.sh fuzz/Makefile.in fuzz/Makefile.am fuzz/*.cpp fuzz/uclient.cfg diff --git a/Makefile.in b/Makefile.in index 3ee726ca..f696e8d9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -452,7 +452,7 @@ ACLOCAL_AMFLAGS = -I m4 configfiles = userver.service EXTRA_DIST = $(configfiles:%=%.in) \ cdb configure.help TODO LICENSE* README* *.spec* \ - doc/Doxyfile doc/readme.txt shtool *.awk .travis.yml autogen.sh nativejson-benchmark \ + doc/Doxyfile doc/readme.txt doc/style.css shtool *.awk .travis.yml autogen.sh nativejson-benchmark \ ULib.m4 rpm.sh rpmpkgreq.lst rpmpkgreq.lst.suse openwrt CODE_OF_CONDUCT.md CONTRIBUTING.md \ fuzz/http1-corpus fuzz/http2-corpus fuzz/build_libFuzzer.sh fuzz/Makefile.in fuzz/Makefile.am fuzz/*.cpp fuzz/uclient.cfg diff --git a/README.md b/README.md index effa04ed..8ff704a0 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ The current version offers the following features : * Browser cache management (headers: If-Modified-Since/Last-modified). * Chunk-encoding transfers support. * HTTP multi-range request support. - * Memory caching of document root for (small) static pages with smart gzip compression and CSS/JS reduction. + * Memory caching of document root for (small) static pages with smart (gzip-zopfli,brotli) compression and CSS/JS reduction. * Support for automatic update of caching document root with inotify (on Linux). * Support for pipelining. * Support for virtual hosts (also with SSL). @@ -43,6 +43,7 @@ The current version offers the following features : * Support for running Ruby on Rails applications natively (experimental). * Support for running natively PHP applications whith a php (embedded) library (experimental). * Support for load balance between physical server via udp brodcast (experimental). + * Support for serialize object by [FlatBuffer schema-less](http://google.github.io/flatbuffers/index.html) like implementation. * Preforking mode to improve concurrency with dedicated process for long-time request. * Support for Windows (without preforking). * Customizable builds (you can remove unneeded functionality). diff --git a/configure b/configure index 5e0828be..48f0fa38 100755 --- a/configure +++ b/configure @@ -26849,6 +26849,8 @@ main () if (*(data + i) != *(data3 + i)) return 14; close (fd); + free (data); + free (data3); return 0; } _ACEOF @@ -30476,7 +30478,7 @@ $as_echo_n "checking for PostgreSQL client libraries... " >&6; } POSTGRESQL_CPPFLAGS="-I`$PG_CONFIG --includedir` -I`$PG_CONFIG --includedir-server`" POSTGRESQL_VERSION=`$PG_CONFIG --version | sed -e 's#PostgreSQL ##'` - if test -f "$postgresql_libdir/libpgport.a" -o -f "$postgresql_libdir/libpgport.so" -o -f "/usr/lib/libpgport.a" -o -f "/usr/lib/libpgport.so"; then + if test -f "$postgresql_libdir/libpgport.so" -o -f "/usr/lib/libpgport.so"; then POSTGRESQL_LIBS="-lpq -lpgport" else POSTGRESQL_LIBS="-lpq" @@ -34202,7 +34204,7 @@ fi ## ------------------------------------------------------------------------------------- if test "$enable_debug" != "yes"; then - MAYBE_FLAGS="$MAYBE_FLAGS -Winline -Wno-unused-parameter -Wno-unused-variable" + MAYBE_FLAGS="$MAYBE_FLAGS -Wno-unused-parameter -Wno-unused-variable" # -Winline else ## _FORTIFY_SOURCE is enabled by default from g++ 4.7.2 MAYBE_FLAGS="$MAYBE_FLAGS -Wunsafe-loop-optimizations -Wno-unused-parameter -rdynamic -fdiagnostics-color=auto -Wmisleading-indentation" diff --git a/configure.ac b/configure.ac index 45cc6b61..9064483f 100644 --- a/configure.ac +++ b/configure.ac @@ -2433,7 +2433,7 @@ if test "$ac_cv_c_compiler_gnu" = "yes" -a "x$OPERATINGSYSTEM" = xlinux; then ## ------------------------------------------------------------------------------------- if test "$enable_debug" != "yes"; then - MAYBE_FLAGS="$MAYBE_FLAGS -Winline -Wno-unused-parameter -Wno-unused-variable" + MAYBE_FLAGS="$MAYBE_FLAGS -Wno-unused-parameter -Wno-unused-variable" # -Winline else ## _FORTIFY_SOURCE is enabled by default from g++ 4.7.2 MAYBE_FLAGS="$MAYBE_FLAGS -Wunsafe-loop-optimizations -Wno-unused-parameter -rdynamic -fdiagnostics-color=auto -Wmisleading-indentation" diff --git a/doc/Doxyfile b/doc/Doxyfile index 5066ee20..e5ecc197 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1059,7 +1059,7 @@ HTML_STYLESHEET = # see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = style.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note diff --git a/doc/style.css b/doc/style.css new file mode 100644 index 00000000..6045a973 --- /dev/null +++ b/doc/style.css @@ -0,0 +1,396 @@ +body, +#projectname, +table, +div, +p, +dl, +.title, +.tabs, +.tabs2, +.tabs3, +#nav-tree .label { + font-family: roboto, sans-serif; +} + +#commonprojectlogo { + padding: 5px 0px 5px 15px; +} + +#projectname { + color: #00bcd4; + font-size: 280%; + padding: 15px 0px; + font-weight: 300; +} + +#titlearea { + border-bottom: 2px solid #e5e5e5; +} + +.title { + color: #212121; + font: 300 34px/40px Roboto,sans-serif; +} + +#nav-tree { + background-color: #fff; +} + +#navrow1, #navrow2 { + border-bottom: 2px solid #e7e7e7; +} + +.tabs, .tabs2, .tabs3 { + font-size: 14px; +} + +.tabs, +.tabs2, +.tabs3, +.tablist li, +.tablist li.current a { + background-image: none; +} + +.tablist { + list-style: none; +} + +.tablist li, .tablist li p { + margin: 0; +} + +.tablist li a, +.tablist li.current a { + color: #757575; + text-shadow: none; +} + +.tablist li.current a { + background: #00bcd4; + color: #fff; +} + +.tablist a { + background-image: none; + border-right: 2px solid #e5e5e5; + font-weight: normal; +} + +.tablist a:hover, +.tablist li.current a:hover { + background-image: none; + text-decoration: underline; + text-shadow: none; +} + +.tablist a:hover { + color: #00bcd4; +} + +.tablist li.current a:hover { + color: #fff; +} + +div.header { + background-color: #f7f7f7; + background-image: none; + border-bottom: none; +} + +#MSearchBox { + border: 1px solid #ccc; + border-radius: 5px; + display: inline-block; + height: 20px; + right: 10px; +} + +#MSearchBox .left, +#MSearchBox .right, +#MSearchField { + background: none; +} + +a.SelectItem:hover { + background-color: #00bcd4; +} + +#nav-tree { + background-image: none; +} + +#nav-tree .selected { + background-image: none; + text-shadow: none; + background-color: #f7f7f7; +} + +#nav-tree a { + color: #212121; +} + +#nav-tree .selected a { + color: #0288d1; +} + +#nav-tree .item:hover { + background-color: #f7f7f7; +} + +#nav-tree .item:hover a { + color: #0288d1; +} + +#nav-tree .label { + font-size: 13px; +} + +#nav-sync { + display: none; +} + +.ui-resizable-e { + background: #ebebeb; + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; +} + +.contents tr td .image { + margin-top: 24px; +} + +.image { + text-align: left; + margin-bottom: 8px; +} + +a:link, +a:visited, +.contents a:link, +.contents a:visited, +a.el { + color: #0288d1; + font-weight: normal; + text-decoration: none; +} + +div.contents { + margin-right: 12px; +} + +.directory tr, .directory tr.even { + background: #7cb342; + border-top: 1px solid #7cb342; +} + +.directory td, +.directory td.entry, +.directory td.desc { + background: rgba(255,255,255,.95); + border-left: none; + color: #212121; + padding-top: 10px; + padding-bottom: 10px; + padding-left: 8px; + padding-right: 8px; +} + +.directory tr#row_0_ { + border-top-color: #7cb342; +} + +.directory tr#row_0_ td { + background: #7cb342; + color: #fff; + font-size: 18px; +} + +.memSeparator { + border-bottom: none; +} + +.memitem { + background: #7cb342; +} + +.memproto, dl.reflist dt { + background: #7cb342; + background-image: none; + border: none; + box-shadow: none; + -webkit-box-shadow: none; + color: #fff; + text-shadow: none; +} + +.memproto .memtemplate, +.memproto a.el, +.memproto .paramname { + color: #fff; +} + +.memdoc, dl.reflist dd { + border: none; + background-color: rgba(255,255,255,.95); + background-image: none; + box-shadow: none; + -webkit-box-shadow: none; + -webkit-border-bottom-left-radius: 0; + -webkit-border-bottom-right-radius: 0; +} + +.memitem, table.doxtable, table.memberdecls { + margin-bottom: 24px; +} + +table.doxtable th { + background: #7cb342; +} + +table.doxtable tr { + background: #7cb342; + border-top: 1px solid #7cb342; +} + +table.doxtable td, table.doxtable th { + border: none; + padding: 10px 8px; +} + +table.doxtable td { + background-color: rgba(255,255,255,.95); +} + +.memberdecls { + background: #7cb342; + border-top: 1px solid #7cb342; +} + +.memberdecls .heading h2 { + border-bottom: none; + color: #fff; + font-size: 110%; + font-weight: bold; + margin: 0 0 0 6px; +} + +.memberdecls tr:not(.heading) td { + background-color: rgba(255,255,255,.95); +} + +h1, h2, h2.groupheader, h3, h4, h5, h6 { + color: #212121; +} + +h1 { + border-bottom: 1px solid #ebebeb; + font: 400 28px/32px Roboto,sans-serif; + letter-spacing: -.01em; + margin: 40px 0 20px; + padding-bottom: 3px; +} + +h2, h2.groupheader { + border-bottom: 1px solid #ebebeb; + font: 400 23px/32px Roboto,sans-serif; + letter-spacing: -.01em; + margin: 40px 0 20px; + padding-bottom: 3px; +} + +h3 { + font: 500 20px/32px Roboto,sans-serif; + margin: 32px 0 16px; +} + +h4 { + font: 500 18px/32px Roboto,sans-serif; + margin: 32px 0 16px; +} + +ol, +ul { + margin: 0; + padding-left: 40px; +} + +ol { + list-style: decimal outside; +} + +ol ol { + list-style-type: lower-alpha; +} + +ol ol ol { + list-style-type: lower-roman; +} + +ul { + list-style: disc outside; +} + +li, +li p { + margin: 8px 0; + padding: 0; +} + +div.summary +{ + float: none; + font-size: 8pt; + padding-left: 5px; + width: calc(100% - 10px); + text-align: left; + display: block; +} + +div.ingroups { + margin-top: 8px; +} + +div.fragment { + border: 1px solid #ddd; + color: #455a64; + font: 14px/20px Roboto Mono, monospace; + padding: 8px; +} + +div.line { + line-height: 1.5; + font-size: inherit; +} + +code, pre { + color: #455a64; + background: #f7f7f7; + font: 400 100% Roboto Mono,monospace; + padding: 1px 4px; +} + +span.preprocessor, span.comment { + color: #0b8043; +} + +span.keywordtype { + color: #0097a7; +} + +.paramname { + color: #ef6c00; +} + +.memTemplParams { + color: #ef6c00; +} + +span.mlabel { + background: rgba(255,255,255,.25); + border: none; +} + +blockquote { + border: 1px solid #ddd; +} diff --git a/include/Makefile.am b/include/Makefile.am index a1d4a853..8d290b27 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -40,6 +40,7 @@ TO_INC = ulib/README \ ulib/json/*.h \ ulib/query/*.h \ ulib/replace/*.h \ + ulib/serialize/*.h \ ulib/ssh/net/*.h \ ulib/ssl/*.h \ ulib/ssl/mime/*.h \ diff --git a/include/Makefile.in b/include/Makefile.in index fc05d15b..03e0207e 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -462,6 +462,7 @@ TO_INC = ulib/README \ ulib/json/*.h \ ulib/query/*.h \ ulib/replace/*.h \ + ulib/serialize/*.h \ ulib/ssh/net/*.h \ ulib/ssl/*.h \ ulib/ssl/mime/*.h \ diff --git a/include/ulib/all.h b/include/ulib/all.h index 29850df2..306b88b2 100644 --- a/include/ulib/all.h +++ b/include/ulib/all.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #ifdef USE_PARSER diff --git a/include/ulib/base/macro.h b/include/ulib/base/macro.h index b7a3acfc..10a3b258 100644 --- a/include/ulib/base/macro.h +++ b/include/ulib/base/macro.h @@ -350,6 +350,15 @@ static inline void u_put_unalignedp64( void* p, uint64_t val) { s # define u_parse_unalignedp32(p) ((uint32_t)(p)[0]<<24|(p)[1]<<16|(ptr)[2]<< 8|(ptr)[3]) #endif +#if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408 && !defined(__clang__) // __builtin_bswap16 was missing prior to GCC 4.8 +# define U_BYTESWAP16(x) (uint16_t)(__builtin_bswap32((uint32_t)(x) << 16)) +#else +# define U_BYTESWAP16 __builtin_bswap16 +#endif + +#define U_BYTESWAP32 __builtin_bswap32 +#define U_BYTESWAP64 __builtin_bswap64 + /** * u_get_unaligned - get value from possibly mis-aligned location * diff --git a/include/ulib/base/utility.h b/include/ulib/base/utility.h index 5bd9c6d9..4efe6cd9 100644 --- a/include/ulib/base/utility.h +++ b/include/ulib/base/utility.h @@ -747,12 +747,12 @@ U_BOOLEAN_VALUE = 10, // bool value U_LREAL_VALUE = 20 // long double value } ValueType; -static inline uint32_t u_getTag( uint64_t val) { return (val >> U_VALUE_TAG_SHIFT) & U_VALUE_TAG_MASK; } +static inline uint8_t u_getTag( uint64_t val) { return (val >> U_VALUE_TAG_SHIFT) & U_VALUE_TAG_MASK; } static inline uint64_t u_getPayload(uint64_t val) { return (val & U_VALUE_PAYLOAD_MASK); } -static inline uint64_t u_getValue(uint16_t tag, void* payload) +static inline uint64_t u_getValue(uint8_t tag, void* payload) { - U_INTERNAL_TRACE("u_getValue(%hu,%p)", tag, payload) + U_INTERNAL_TRACE("u_getValue(%u,%p)", tag, payload) U_INTERNAL_ASSERT(payload <= (void*)U_VALUE_PAYLOAD_MASK) @@ -761,7 +761,7 @@ static inline uint64_t u_getValue(uint16_t tag, void* payload) ((uint64_t)(long)payload & U_VALUE_PAYLOAD_MASK); } -static inline void u_setTag(uint16_t tag, uint64_t* pval) { uint64_t payload = u_getPayload(*pval); *pval = u_getValue(tag, (void*)(long)payload); } +static inline void u_setTag(uint8_t tag, uint64_t* pval) { uint64_t payload = u_getPayload(*pval); *pval = u_getValue(tag, (void*)(long)payload); } #if defined(USE_PGSQL) && defined(LIBPGPORT_NOT_FOUND) static inline void pg_qsort(void* a, size_t n, size_t es, int (*cmp)(const void*, const void*)) { qsort(a, n, es, cmp); } diff --git a/include/ulib/container/hash_map.h b/include/ulib/container/hash_map.h index cf7fee56..2daac621 100644 --- a/include/ulib/container/hash_map.h +++ b/include/ulib/container/hash_map.h @@ -93,8 +93,6 @@ public: { U_TRACE_UNREGISTER_OBJECT(0, UHashMap) - U_INTERNAL_ASSERT_EQUALS(_length, 0) - if (_capacity) _deallocate(); } @@ -216,13 +214,6 @@ public: void* operator[](const UString& k) { return (lkey = k.rep, at()); } void* operator[](const UStringRep* k) { return (lkey = k, at()); } - template T* get(const UString& k) - { - U_TRACE(0, "UHashMap::get(%V)", k.rep) - - return (T*) operator[](k); - } - // after called find() (don't make the lookup) void eraseAfterFind(); @@ -265,6 +256,8 @@ public: static void setNodePointer(char* table, uint32_t idx) { node = (UHashMapNode*)(table + (idx * UHashMapNode::size())); } + static void nextNodePointer() { node = (UHashMapNode*)((char*)node + UHashMapNode::size()); } + // traverse the hash table for all entry bool first() @@ -435,6 +428,7 @@ protected: U_CHECK_MEMORY + U_INTERNAL_ASSERT_EQUALS(_length, 0) U_INTERNAL_ASSERT_MAJOR(_capacity, 1) UMemoryPool::_free(info, _capacity, 1+UHashMapNode::size()); diff --git a/include/ulib/container/vector.h b/include/ulib/container/vector.h index ea8f6463..d82e1598 100644 --- a/include/ulib/container/vector.h +++ b/include/ulib/container/vector.h @@ -38,6 +38,7 @@ class UNoCatPlugIn; template class UVector; template class UOrmTypeHandler; template class UJsonTypeHandler; +template class UFlatBufferTypeHandler; typedef UVector UVectorUString; @@ -429,6 +430,7 @@ private: template friend class UOrmTypeHandler; template friend class UJsonTypeHandler; + template friend class UFlatBufferTypeHandler; }; template class U_EXPORT UVector : public UVector { diff --git a/include/ulib/internal/memory_pool.h b/include/ulib/internal/memory_pool.h index f80f5fc9..298e58ab 100644 --- a/include/ulib/internal/memory_pool.h +++ b/include/ulib/internal/memory_pool.h @@ -56,7 +56,6 @@ * 32 sizeof(UQueryNode) * 32 sizeof(USOAPFault) * 32 sizeof(UTokenizer) - * 32 sizeof(UHashMapNode) <== * 32 sizeof(UXMLAttribute) * 32 sizeof(UTree) * ------------------------- @@ -145,7 +144,6 @@ * 40 sizeof(UStringRep) <== * 40 sizeof(UTokenizer) * 40 sizeof(USOAPObject) - * 40 sizeof(UHashMapNode) <== * 40 sizeof(UTree) * ------------------------- * U_STACK_TYPE_1 @@ -238,7 +236,6 @@ * 16 sizeof(UTokenizer) * 16 sizeof(UStringRep) <== * 16 sizeof(USOAPObject) - * 16 sizeof(UHashMapNode) <== * ------------------------- * U_STACK_TYPE_1 * @@ -324,7 +321,6 @@ * 20 sizeof(UQueryNode) * 20 sizeof(USOAPFault) * 20 sizeof(UTokenizer) - * 20 sizeof(UHashMapNode) <== * 24 sizeof(USOAPObject) * 24 sizeof(UTree) * 28 sizeof(UStringRep) <== diff --git a/include/ulib/json/value.h b/include/ulib/json/value.h index 79b2e648..1b62e380 100644 --- a/include/ulib/json/value.h +++ b/include/ulib/json/value.h @@ -14,7 +14,7 @@ #ifndef ULIB_VALUE_H #define ULIB_VALUE_H 1 -#include +#include #include @@ -71,10 +71,8 @@ public: U_MEMORY_DEALLOCATOR union jval { - int sint; - unsigned int uint; - uint64_t ival; - double real; + uint64_t ival; + double real; }; static int jsonParseFlags; @@ -222,7 +220,7 @@ public: U_RETURN(false); } - uint32_t getTag() const { return getTag(value.ival); } + uint8_t getTag() const { return getTag(value.ival); } bool isNull() const { @@ -233,20 +231,7 @@ public: U_RETURN(false); } - bool isBool() const - { - U_TRACE_NO_PARAM(0, "UValue::isBool()") - - uint32_t type = getTag(); - - if (type == U_TRUE_VALUE || - type == U_FALSE_VALUE) - { - U_RETURN(true); - } - - U_RETURN(false); - } + bool isBool() const { return isBool(getTag()); } bool isInt() const { @@ -275,15 +260,6 @@ public: U_RETURN(false); } - bool isNumeric() const - { - U_TRACE_NO_PARAM(0, "UValue::isNumeric()") - - if (getTag() <= U_UINT_VALUE) U_RETURN(true); - - U_RETURN(false); - } - bool isString() const { U_TRACE_NO_PARAM(0, "UValue::isString()") @@ -313,21 +289,23 @@ public: union jval getKey() const { return pkey; } - int getInt() const { return value.sint; } - unsigned int getUInt() const { return value.uint; } + int64_t getInt64() const { return -(long)getPayload(); } + uint64_t getUInt64() const { return (long)getPayload(); } UString getString() { return getString(value.ival); } bool getBool() const { return (getTag() == U_TRUE_VALUE); } double getDouble() const { return value.real; } + bool isNumeric() const { return isNumeric(getTag(value.ival)); } bool isStringUTF() const { return isStringUTF(value.ival); } bool isStringOrUTF() const { return isStringOrUTF(value.ival); } - bool isArrayOrObject() const { return isArrayOrObject(value.ival); } + bool isArrayOrObject() const { return isArrayOrObject(getTag(value.ival)); } static uint32_t getStringSize(const union jval value) { return getString(value.ival).size(); } - long long getNumber() const { return (isDouble() ? llrint(value.real) : (long long)(long)getPayload()); } + int64_t getInt() const { return (isInt() ? getInt64() : getUInt64()); } + int64_t getNumber() const { return (isDouble() ? llrint(value.real) : getInt()); } // manage values in array or object @@ -375,7 +353,7 @@ public: { U_TRACE_NO_PARAM(0, "UValue::output()") - UString result(size+100U); + UString result(U_max(size+100U,U_CAPACITY)); pstringify = result.data(); // buffer to stringify json @@ -418,11 +396,11 @@ public: U_INTERNAL_DUMP("result(%u) = %V", result.size(), result.rep) } - template static void toJSON(const UString& name, UJsonTypeHandler member) + template static void toJSON(const UString& name, UJsonTypeHandler member) { U_TRACE(0, "UValue::toJSON(%V,%p)", name.rep, &member) - addString(name); + addStringParser(U_STRING_TO_PARAM(name)); member.toJSON(); } @@ -431,7 +409,7 @@ public: { U_TRACE(0, "UValue::toJSON(%.*S,%u,%p)", len, name, len, &member) - addString(name, len); + addStringParser(name, len); member.toJSON(); } @@ -446,6 +424,42 @@ public: else member.clear(); } + // JSON <=> UFlatBuffer + + UString toFlatBuffer() const + { + U_TRACE_NO_PARAM(0, "UValue::toFlatBuffer()") + + UString result; + UFlatBuffer fb; + + toFlatBuffer(fb, result); + + U_RETURN_STRING(result); + } + + void toFlatBuffer(UFlatBuffer& fb) const + { + U_TRACE(0, "UValue::toFlatBuffer(%p)", &fb) + + UString result; + + toFlatBuffer(fb, result); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UValue::fromFlatBuffer(%p)", &fb) + + U_ASSERT(empty()) + + initParser(); + + fromFlatBufferToJSON(fb); + + value.ival = o.ival; + } + // ======================================================================================================================= // An in-place JSON element reader (@see http://www.codeproject.com/Articles/885389/jRead-an-in-place-JSON-element-reader) // ======================================================================================================================= @@ -570,7 +584,7 @@ public: const char* dump(bool _reset) const; static const char* getJReadErrorDescription(); - static const char* getDataTypeDescription(uint32_t type); + static const char* getDataTypeDescription(uint8_t type); #else static const char* getJReadErrorDescription() { return ""; } static const char* getDataTypeDescription(uint32_t) { return ""; } @@ -582,6 +596,7 @@ protected: value; static uint32_t size; + static UFlatBuffer* pfb; static char* pstringify; // buffer to stringify json typedef struct parser_stack_data { @@ -603,12 +618,44 @@ protected: } static void nextParser(); - - static uint32_t getTag(uint64_t val) + + static void initStackParser(bool obj) + { + U_TRACE(0, "UValue::initStackParser(%b)", obj) + + ++pos; + + U_INTERNAL_DUMP("pos = %u", pos) + + U_INTERNAL_ASSERT_MINOR(pos, U_JSON_PARSE_STACK_SIZE) + +# ifndef HAVE_OLD_IOSTREAM + sd[pos] = {0, U_NULLPTR, obj}; +# else + sd[pos].keys = 0; + sd[pos].tails = U_NULLPTR; + sd[pos].obj = obj; +# endif + } + + static bool isBool(uint8_t type) + { + U_TRACE(0, "UValue::isBool(%u)", type) + + if (type == U_TRUE_VALUE || + type == U_FALSE_VALUE) + { + U_RETURN(true); + } + + U_RETURN(false); + } + + static uint8_t getTag(uint64_t val) { U_TRACE(0, "UValue::getTag(%#llx)", val) - uint32_t tag = ((int64_t)val <= (int64_t)U_VALUE_NAN_MASK ? (uint32_t)U_REAL_VALUE : u_getTag(val)); + uint8_t tag = ((int64_t)val <= (int64_t)U_VALUE_NAN_MASK ? (uint32_t)U_REAL_VALUE : u_getTag(val)); U_INTERNAL_DUMP("tag = %u", tag) @@ -617,9 +664,9 @@ protected: U_RETURN(tag); } - static uint64_t getValue(uint16_t tag, void* payload) + static uint64_t getValue(uint8_t tag, void* payload) { - U_TRACE(0+256, "UValue::getValue(%hu,%p)", tag, payload) + U_TRACE(0, "UValue::getValue(%u,%p)", tag, payload) U_INTERNAL_ASSERT(payload <= (void*)U_VALUE_PAYLOAD_MASK) @@ -632,30 +679,6 @@ protected: U_RETURN(val); } - static void addString(const char* ptr, uint32_t sz) - { - U_TRACE(0, "UValue::addString(%.*S,%u)", sz, ptr, sz) - - if (sz) - { - UStringRep* rep; - - U_NEW(UStringRep, rep, UStringRep(ptr, sz)); - - o.ival = getValue(U_STRING_VALUE, rep); - } - else - { - UStringRep::string_rep_null->hold(); - - o.ival = getValue(U_STRING_VALUE, UStringRep::string_rep_null); - } - - nextParser(); - } - - static void addString(const UString& str) { addString(U_STRING_TO_PARAM(str)); } - #ifdef DEBUG static uint32_t cnt_real, cnt_mreal; #endif @@ -733,7 +756,7 @@ protected: { U_TRACE_NO_PARAM(0, "UValue::emitKey()") - uint32_t type = getTag(pkey.ival); + uint8_t type = getTag(pkey.ival); if (type == U_STRING_VALUE) emitString((UStringRep*)u_getPayload(pkey.ival)); else @@ -747,6 +770,11 @@ protected: void stringify() const; void prettify(uint32_t indent) const; + void toFlatBufferFromJSON() const; + void fromFlatBufferToJSON(UFlatBuffer& fb); + + void toFlatBuffer(UFlatBuffer& fb, UString& result) const; + UValue* toNode() const { return toNode(value.ival); } uint64_t getPayload() const { return u_getPayload(value.ival); } @@ -773,7 +801,7 @@ protected: { U_TRACE(0+256, "UValue::isStringOrUTF(%#llx)", value) - uint32_t type = getTag(value); + uint8_t type = getTag(value); if (type == U_STRING_VALUE || type == U_UTF_VALUE) @@ -784,13 +812,24 @@ protected: U_RETURN(false); } - static bool isArrayOrObject(uint64_t value) + static bool isNumeric(uint8_t type) { - U_TRACE(0+256, "UValue::isArrayOrObject(%#llx)", value) + U_TRACE(0, "UValue::isNumeric(%u)", type) - uint32_t type = getTag(value); + U_DUMP("type = %S", getDataTypeDescription(type)) - if (type == U_ARRAY_VALUE || + if (type <= U_UINT_VALUE) U_RETURN(true); + + U_RETURN(false); + } + + static bool isArrayOrObject(uint8_t type) + { + U_TRACE(0, "UValue::isArrayOrObject(%u)", type) + + U_DUMP("type = %S", getDataTypeDescription(type)) + + if (type == U_ARRAY_VALUE || type == U_OBJECT_VALUE) { U_RETURN(true); @@ -814,6 +853,47 @@ protected: return getValue(tag, U_NULLPTR); } + static void setArrayEmpty() + { + U_TRACE_NO_PARAM(0, "UValue::setArrayEmpty()") + + o.ival = listToValue(U_ARRAY_VALUE, U_NULLPTR); + } + + static void setObjectEmpty() + { + U_TRACE_NO_PARAM(0, "UValue::setObjectEmpty()") + + o.ival = listToValue(U_OBJECT_VALUE, U_NULLPTR); + } + + static void setArray() + { + U_TRACE_NO_PARAM(0, "UValue::setArray()") + + U_INTERNAL_DUMP("pos = %d sd[0].obj = %b sd[0].tails = %p sd[0].keys = %#llx", + pos, sd[0].obj, sd[0].tails, sd[0].keys) + + U_INTERNAL_ASSERT_DIFFERS(pos, -1) + U_INTERNAL_ASSERT_EQUALS(sd[pos].obj, false) + + o.ival = listToValue(U_ARRAY_VALUE, sd[pos--].tails); + } + + static void setObject() + { + U_TRACE_NO_PARAM(0, "UValue::setObject()") + + U_INTERNAL_DUMP("pos = %d sd[0].obj = %b sd[0].tails = %p sd[0].keys = %#llx", + pos, sd[0].obj, sd[0].tails, sd[0].keys) + + U_INTERNAL_ASSERT(sd[pos].obj) + U_INTERNAL_ASSERT_DIFFERS(pos, -1) + U_INTERNAL_ASSERT_EQUALS(sd[pos].keys, 0) + + o.ival = listToValue(U_OBJECT_VALUE, sd[pos--].tails); + } + static UValue* insertAfter(UValue* tail, uint64_t value) { U_TRACE(0, "UValue::insertAfter(%p,%#llx)", tail, value) @@ -835,17 +915,148 @@ protected: U_RETURN_POINTER(node, UValue); } - void setString(UStringRep* rep) + static void setNull() { - U_TRACE(0, "UValue::setString(%p)", rep) + U_TRACE_NO_PARAM(0, "UValue::setNull()") - U_INTERNAL_DUMP("rep = %V", rep) - - rep->hold(); - - value.ival = getValue(U_STRING_VALUE, rep); + o.ival = u_getValue(U_NULL_VALUE, U_NULLPTR); } + static void setBool(bool flag) + { + U_TRACE(0, "UValue::setBool(%b)", flag) + + o.ival = u_getValue(flag ? U_TRUE_VALUE : U_FALSE_VALUE, U_NULLPTR); + } + + static void setDouble(double f) + { + U_TRACE(0, "UValue::setDouble(%g)", f) + + o.real = f; + + U_ASSERT_EQUALS(getTag(o.ival), U_REAL_VALUE) + } + + void setString(const UString& x) + { + U_TRACE(0, "UValue::setString(%V)", x.rep) + + x.rep->hold(); + + o.ival = getValue(U_STRING_VALUE, x.rep); + } + + static void setValue(uint8_t tag, void* payload) + { + U_TRACE(0, "UValue::setValue(%u,%p)", tag, payload) + + o.ival = u_getValue(tag, payload); + + U_ASSERT_EQUALS(getTag(o.ival), tag) + + U_INTERNAL_DUMP("o.ival = %llu", o.ival) + } + +#if SIZEOF_LONG == 4 + static void setValue(uint8_t tag, char* pval) { setValue(tag, (void*)*pval); } + static void setValue(uint8_t tag, unsigned char* pval) { setValue(tag, (void*)*pval); } + static void setValue(uint8_t tag, short* pval) { setValue(tag, (void*)*pval); } + static void setValue(uint8_t tag, unsigned short* pval) { setValue(tag, (void*)*pval); } + static void setValue(uint8_t tag, int* pval) { setValue(tag, (void*)*pval); } + static void setValue(uint8_t tag, unsigned int* pval) { setValue(tag, (void*)*pval); } +#else + static void setValue(uint8_t tag, char* pval) { setValue(tag, (void*)(*pval & 0x00000000FFFFFFFFULL)); } + static void setValue(uint8_t tag, unsigned char* pval) { setValue(tag, (void*)(*pval & 0x00000000FFFFFFFFULL)); } + static void setValue(uint8_t tag, short* pval) { setValue(tag, (void*)(*pval & 0x00000000FFFFFFFFULL)); } + static void setValue(uint8_t tag, unsigned short* pval) { setValue(tag, (void*)(*pval & 0x00000000FFFFFFFFULL)); } + static void setValue(uint8_t tag, int* pval) { setValue(tag, (void*)(*pval & 0x00000000FFFFFFFFULL)); } + static void setValue(uint8_t tag, unsigned int* pval) { setValue(tag, (void*)(*pval & 0x00000000FFFFFFFFULL)); } +#endif + + static void setUInt64(uint64_t l) + { + U_TRACE(0, "UValue::setUInt64(%llu)", l) + + if (l > U_VALUE_PAYLOAD_MASK) setDouble(l); + else setValue(U_UINT_VALUE, (void*)(l & U_VALUE_PAYLOAD_MASK)); + } + + static void setInt64(int64_t l) + { + U_TRACE(0, "UValue::setInt64(%lld)", l) + + U_INTERNAL_ASSERT_MINOR(l, 0) + + uint64_t i = -l; + + if (i > U_VALUE_PAYLOAD_MASK) setDouble(i); + else setValue(U_INT_VALUE, (void*)(i & U_VALUE_PAYLOAD_MASK)); + } + + static void setNumber64(int64_t l) + { + U_TRACE(0, "UValue::setNumber(%lld)", l) + + if (l < 0) setInt64(l); + else setUInt64(l); + } + + static void setNumber32(int32_t l) + { + U_TRACE(0, "UValue::setNumber32(%ld)", l) + + if (l < 0) setValue(U_INT_VALUE, (void*)(-l & 0x00000000FFFFFFFFULL)); + else setValue(U_UINT_VALUE, (void*)( l & 0x00000000FFFFFFFFULL)); + } + + static void setLong(long l) + { + U_TRACE(0, "UValue::setLong(%ld)", l) + +# if SIZEOF_LONG == 4 + setNumber32(l); +# else + setNumber64(l); +# endif + } + + static void setULong(unsigned long l) + { + U_TRACE(0, "UValue::setULong(%lu)", l) + +# if SIZEOF_LONG == 8 + setUInt64(l); +# else + setValue(U_UINT_VALUE, (void*)l); +# endif + } + + static void addString(const char* ptr, uint32_t sz) + { + U_TRACE(0, "UValue::addString(%.*S,%u)", sz, ptr, sz) + + if (sz) + { + UStringRep* rep; + + U_NEW(UStringRep, rep, UStringRep(ptr, sz)); + + setValue(U_STRING_VALUE, rep); + } + else + { + UStringRep::string_rep_null->hold(); + + setValue(U_STRING_VALUE, UStringRep::string_rep_null); + } + } + + static void addStringParser(const char* ptr, uint32_t sz) { addString(ptr, sz); nextParser(); } + + static void addString( const UString& x) { addString( U_STRING_TO_PARAM(x)); } + static void addStringParser(const UString& x) { addStringParser(U_STRING_TO_PARAM(x)); } + static UString getString(uint64_t value); private: @@ -856,6 +1067,7 @@ private: static UString jread_object(UTokenizer& tok) U_NO_EXPORT; static UString jread_object(UTokenizer& tok, uint32_t keyIndex) U_NO_EXPORT; + friend class UString; friend class UValueIter; friend class UTokenizer; friend UValueIter begin(const union jval); @@ -939,7 +1151,7 @@ private: * * Take as example the following (simplified) class: * - * class Person { + * class Person { * public: * int age; * UString lastName; @@ -1009,28 +1221,11 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - ++UValue::pos; - - U_INTERNAL_ASSERT_MINOR(UValue::pos, U_JSON_PARSE_STACK_SIZE) - -# ifndef HAVE_OLD_IOSTREAM - UValue::sd[UValue::pos] = {0, U_NULLPTR, true}; -# else - UValue::sd[UValue::pos].keys = 0; - UValue::sd[UValue::pos].tails = U_NULLPTR; - UValue::sd[UValue::pos].obj = true; -# endif + UValue::initStackParser(true); ((T*)pval)->toJSON(); - U_INTERNAL_DUMP("UValue::pos = %d UValue::sd[0].obj = %b UValue::sd[0].tails = %p UValue::sd[0].keys = %#llx", - UValue::pos, UValue::sd[0].obj, UValue::sd[0].tails, UValue::sd[0].keys) - - U_INTERNAL_ASSERT_DIFFERS(UValue::pos, -1) - U_INTERNAL_ASSERT(UValue::sd[UValue::pos].obj) - U_INTERNAL_ASSERT_EQUALS(UValue::sd[UValue::pos].keys, 0) - - UValue::o.ival = UValue::listToValue(U_OBJECT_VALUE, UValue::sd[UValue::pos--].tails); + UValue::setObject(); if (UValue::pos != -1) UValue::nextParser(); } @@ -1112,7 +1307,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - UValue::o.ival = UValue::getValue(U_NULL_VALUE, U_NULLPTR); + UValue::setNull(); UValue::nextParser(); } @@ -1149,7 +1344,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - UValue::o.ival = UValue::getValue(*(bool*)pval ? U_TRUE_VALUE : U_FALSE_VALUE, U_NULLPTR); + UValue::setBool(*(bool*)pval); UValue::nextParser(); } @@ -1186,7 +1381,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - UValue::o.ival = UValue::getValue(U_UINT_VALUE, (void*)(*(char*)pval & 0x00000000FFFFFFFFULL)); + UValue::setValue(U_UINT_VALUE, (char*)pval); UValue::nextParser(); } @@ -1195,7 +1390,7 @@ public: { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) - *(char*)pval = json.getUInt(); + *(char*)pval = json.getUInt64(); } }; @@ -1223,7 +1418,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - UValue::o.ival = UValue::getValue(U_UINT_VALUE, (void*)(*(unsigned char*)pval & 0x00000000FFFFFFFFULL)); + UValue::setValue(U_UINT_VALUE, (unsigned char*)pval); UValue::nextParser(); } @@ -1232,7 +1427,7 @@ public: { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) - *(unsigned char*)pval = json.getUInt(); + *(unsigned char*)pval = json.getUInt64(); } }; @@ -1260,7 +1455,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - UValue::o.ival = UValue::getValue(U_INT_VALUE, (void*)(*(short*)pval & 0x00000000FFFFFFFFULL)); + UValue::setValue(U_INT_VALUE, (short*)pval); UValue::nextParser(); } @@ -1269,7 +1464,7 @@ public: { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) - *(short*)pval = json.getUInt(); + *(short*)pval = json.getUInt64(); } }; @@ -1297,7 +1492,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - UValue::o.ival = UValue::getValue(U_UINT_VALUE, (void*)(*(unsigned short*)pval & 0x00000000FFFFFFFFULL)); + UValue::setValue(U_UINT_VALUE, (unsigned short*)pval); UValue::nextParser(); } @@ -1306,7 +1501,7 @@ public: { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) - *(unsigned short*)pval = json.getUInt(); + *(unsigned short*)pval = json.getUInt64(); } }; @@ -1334,7 +1529,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - UValue::o.ival = UValue::getValue(U_INT_VALUE, (void*)(*(int*)pval & 0x00000000FFFFFFFFULL)); + UValue::setNumber32(*(int*)pval); UValue::nextParser(); } @@ -1371,7 +1566,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - UValue::o.ival = UValue::getValue(U_UINT_VALUE, (void*)(*(unsigned int*)pval & 0x00000000FFFFFFFFULL)); + UValue::setValue(U_UINT_VALUE, (unsigned int*)pval); UValue::nextParser(); } @@ -1380,7 +1575,7 @@ public: { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) - *(unsigned int*)pval = json.getUInt(); + *(unsigned int*)pval = json.getUInt64(); } }; @@ -1412,18 +1607,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - long l = *(long*)pval; - - U_INTERNAL_DUMP("pval = %ld", *(long*)pval) - -# if SIZEOF_LONG == 4 - uint32_t type = U_INT_VALUE; -# else - uint32_t type = (l > UINT_MAX || l < INT_MIN ? U_REAL_VALUE : - l > 0 ? U_UINT_VALUE : U_INT_VALUE); -# endif - - UValue::o.ival = UValue::getValue(type, (void*)(l & 0x00000000FFFFFFFFULL)); + UValue::setLong(*(long*)pval); UValue::nextParser(); } @@ -1433,8 +1617,6 @@ public: U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(long*)pval = json.getNumber(); - - U_INTERNAL_DUMP("pval = %ld", *(long*)pval) } }; @@ -1466,15 +1648,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - unsigned long l = *(unsigned long*)pval; - -# if SIZEOF_LONG == 4 - uint32_t type = U_UINT_VALUE; -# else - uint32_t type = (l > UINT_MAX ? U_REAL_VALUE : U_UINT_VALUE); -# endif - - UValue::o.ival = UValue::getValue(type, (void*)(l & 0x00000000FFFFFFFFULL)); + UValue::setULong(*(unsigned long*)pval); UValue::nextParser(); } @@ -1511,14 +1685,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - long long l = *(long long*)pval; - - uint32_t type = (l > UINT_MAX || l < INT_MIN ? U_REAL_VALUE : - l > 0 ? U_UINT_VALUE : U_INT_VALUE); - - U_INTERNAL_DUMP("l = %ld type = %u", l, type) - - UValue::o.ival = UValue::getValue(type, (void*)(l & 0x00000000FFFFFFFFULL)); + UValue::setNumber64(*(int64_t*)pval); UValue::nextParser(); } @@ -1555,9 +1722,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - unsigned long long l = *(unsigned long long*)pval; - - UValue::o.ival = UValue::getValue(l > UINT_MAX ? U_REAL_VALUE : U_UINT_VALUE, (void*)(l & 0x00000000FFFFFFFFULL)); + UValue::setUInt64(*(uint64_t*)pval); UValue::nextParser(); } @@ -1594,7 +1759,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - UValue::o.ival = UValue::getValue(U_REAL_VALUE, (void*)lrintf(*(float*)pval)); + UValue::setDouble(*(float*)pval); UValue::nextParser(); } @@ -1631,7 +1796,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - UValue::o.ival = UValue::getValue(U_REAL_VALUE, (void*)lrint(*(double*)pval)); + UValue::setDouble(*(double*)pval); UValue::nextParser(); } @@ -1668,11 +1833,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") -# ifdef HAVE_LRINTL - UValue::o.ival = UValue::getValue(U_REAL_VALUE, (void*)lrintl(*(long double*)pval)); -# else - UValue::o.ival = UValue::getValue(U_REAL_VALUE, (void*)lrint(*( double*)pval)); -# endif + UValue::setDouble(*(long double*)pval); UValue::nextParser(); } @@ -1709,7 +1870,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - UValue::addString(U_STRING_TO_PARAM(*(UStringRep*)pval)); + UValue::addStringParser(U_STRING_TO_PARAM(*(UStringRep*)pval)); } void fromJSON(UValue& json) @@ -1752,7 +1913,7 @@ public: { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::toJSON()") - UValue::addString(*(UString*)pval); + UValue::addStringParser(U_STRING_TO_PARAM(*(UString*)pval)); } void fromJSON(UValue& json) @@ -1820,30 +1981,17 @@ public: uvector* pvec = (uvector*)pval; - if (pvec->_length == 0) UValue::o.ival = UValue::listToValue(U_ARRAY_VALUE, U_NULLPTR); + if (pvec->_length == 0) UValue::setArrayEmpty(); else { const void** ptr = pvec->vec; const void** end = pvec->vec + pvec->_length; - ++UValue::pos; - - U_INTERNAL_ASSERT_MINOR(UValue::pos, U_JSON_PARSE_STACK_SIZE) - -# ifndef HAVE_OLD_IOSTREAM - UValue::sd[UValue::pos] = {0, U_NULLPTR, false}; -# else - UValue::sd[UValue::pos].keys = 0; - UValue::sd[UValue::pos].tails = U_NULLPTR; - UValue::sd[UValue::pos].obj = false; -# endif + UValue::initStackParser(false); do { UJsonTypeHandler(*(T*)(*ptr)).toJSON(); } while (++ptr < end); - U_INTERNAL_ASSERT_DIFFERS(UValue::pos, -1) - U_INTERNAL_ASSERT_EQUALS(UValue::sd[UValue::pos].obj, false) - - UValue::o.ival = UValue::listToValue(U_ARRAY_VALUE, UValue::sd[UValue::pos--].tails); + UValue::setArray(); } if (UValue::pos != -1) UValue::nextParser(); @@ -1863,7 +2011,8 @@ public: U_NEW(T, pitem, T); - U_DUMP("pelement = %p pelement->next = %p pelement->type = (%u,%S)", pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) + U_DUMP("pelement = %p pelement->next = %p pelement->type = (%u,%S)", + pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) UJsonTypeHandler(*pitem).fromJSON(*pelement); @@ -1921,30 +2070,17 @@ public: uvectorbase* pvec = (uvectorbase*)pval; - if (pvec->_length == 0) UValue::o.ival = UValue::listToValue(U_ARRAY_VALUE, U_NULLPTR); + if (pvec->_length == 0) UValue::setArrayEmpty(); else { const void** ptr = pvec->vec; const void** end = pvec->vec + pvec->_length; - ++UValue::pos; + UValue::initStackParser(false); - U_INTERNAL_ASSERT_MINOR(UValue::pos, U_JSON_PARSE_STACK_SIZE) + do { UValue::addStringParser(U_STRING_TO_PARAM(*(const UStringRep*)(*ptr))); } while (++ptr < end); -# ifndef HAVE_OLD_IOSTREAM - UValue::sd[UValue::pos] = {0, U_NULLPTR, false}; -# else - UValue::sd[UValue::pos].keys = 0; - UValue::sd[UValue::pos].tails = U_NULLPTR; - UValue::sd[UValue::pos].obj = false; -# endif - - do { UValue::addString(U_STRING_TO_PARAM(*(const UStringRep*)(*ptr))); } while (++ptr < end); - - U_INTERNAL_ASSERT_DIFFERS(UValue::pos, -1) - U_INTERNAL_ASSERT_EQUALS(UValue::sd[UValue::pos].obj, false) - - UValue::o.ival = UValue::listToValue(U_ARRAY_VALUE, UValue::sd[UValue::pos--].tails); + UValue::setArray(); } if (UValue::pos != -1) UValue::nextParser(); @@ -1962,7 +2098,8 @@ public: { UString item; - U_DUMP("pelement = %p pelement->next = %p pelement->type = (%u,%S)", pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) + U_DUMP("pelement = %p pelement->next = %p pelement->type = (%u,%S)", + pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) UJsonTypeHandler(item).fromJSON(*pelement); @@ -2013,31 +2150,14 @@ public: uhashmap* pmap = (uhashmap*)pval; - if (pmap->first()) + if (pmap->first() == false) UValue::setObjectEmpty(); + else { - ++UValue::pos; - - U_INTERNAL_ASSERT_MINOR(UValue::pos, U_JSON_PARSE_STACK_SIZE) - -# ifndef HAVE_OLD_IOSTREAM - UValue::sd[UValue::pos] = {0, U_NULLPTR, true}; -# else - UValue::sd[UValue::pos].keys = 0; - UValue::sd[UValue::pos].tails = U_NULLPTR; - UValue::sd[UValue::pos].obj = true; -# endif + UValue::initStackParser(true); do { UValue::toJSON(pmap->getKey(), *(pmap->elem())); } while (pmap->next()); - U_INTERNAL_ASSERT_DIFFERS(UValue::pos, -1) - U_INTERNAL_ASSERT(UValue::sd[UValue::pos].obj) - U_INTERNAL_ASSERT_EQUALS(UValue::sd[UValue::pos].keys, 0) - - UValue::o.ival = UValue::listToValue(U_OBJECT_VALUE, UValue::sd[UValue::pos--].tails); - } - else - { - UValue::o.ival = UValue::listToValue(U_OBJECT_VALUE, U_NULLPTR); + UValue::setObject(); } if (UValue::pos != -1) UValue::nextParser(); @@ -2057,7 +2177,8 @@ public: U_NEW(T, pitem, T); - U_DUMP("pelement = %p pelement->next = %p pelement->type = (%u,%S)", pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) + U_DUMP("pelement = %p pelement->next = %p pelement->type = (%u,%S)", + pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) UJsonTypeHandler(*pitem).fromJSON(*pelement); @@ -2113,36 +2234,19 @@ public: UHashMap* pmap = (UHashMap*)pval; - if (pmap->first()) + if (pmap->first() == false) UValue::setObjectEmpty(); + else { - ++UValue::pos; - - U_INTERNAL_ASSERT_MINOR(UValue::pos, U_JSON_PARSE_STACK_SIZE) - -# ifndef HAVE_OLD_IOSTREAM - UValue::sd[UValue::pos] = {0, U_NULLPTR, true}; -# else - UValue::sd[UValue::pos].keys = 0; - UValue::sd[UValue::pos].tails = U_NULLPTR; - UValue::sd[UValue::pos].obj = true; -# endif + UValue::initStackParser(true); do { - UValue::addString(pmap->getKey()); + UValue::addStringParser(U_STRING_TO_PARAM(pmap->getKey())); - UValue::addString(U_STRING_TO_PARAM(*(const UStringRep*)pmap->elem())); + UValue::addStringParser(U_STRING_TO_PARAM(*(const UStringRep*)pmap->elem())); } while (pmap->next()); - U_INTERNAL_ASSERT_DIFFERS(UValue::pos, -1) - U_INTERNAL_ASSERT(UValue::sd[UValue::pos].obj) - U_INTERNAL_ASSERT_EQUALS(UValue::sd[UValue::pos].keys, 0) - - UValue::o.ival = UValue::listToValue(U_OBJECT_VALUE, UValue::sd[UValue::pos--].tails); - } - else - { - UValue::o.ival = UValue::listToValue(U_OBJECT_VALUE, U_NULLPTR); + UValue::setObject(); } if (UValue::pos != -1) UValue::nextParser(); @@ -2160,7 +2264,8 @@ public: { UString item; - U_DUMP("pelement = %p pelement->next = %p pelement->type = (%u,%S)", pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) + U_DUMP("pelement = %p pelement->next = %p pelement->type = (%u,%S)", + pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) UJsonTypeHandler(item).fromJSON(*pelement); @@ -2176,7 +2281,7 @@ public: }; #ifdef U_STDCPP_ENABLE -# include +# include template class U_EXPORT UJsonTypeHandler > : public UJsonTypeHandler_Base { public: @@ -2222,27 +2327,14 @@ public: uint32_t n = pvec->size(); - if (n == 0) UValue::o.ival = UValue::listToValue(U_ARRAY_VALUE, U_NULLPTR); + if (n == 0) UValue::setArrayEmpty(); else { - ++UValue::pos; - - U_INTERNAL_ASSERT_MINOR(UValue::pos, U_JSON_PARSE_STACK_SIZE) - -# ifndef HAVE_OLD_IOSTREAM - UValue::sd[UValue::pos] = {0, U_NULLPTR, false}; -# else - UValue::sd[UValue::pos].keys = 0; - UValue::sd[UValue::pos].tails = U_NULLPTR; - UValue::sd[UValue::pos].obj = false; -# endif + UValue::initStackParser(false); for (uint32_t i = 0; i < n; ++i) UJsonTypeHandler(pvec->at(i)).toJSON(); - U_INTERNAL_ASSERT_DIFFERS(UValue::pos, -1) - U_INTERNAL_ASSERT_EQUALS(UValue::sd[UValue::pos].obj, false) - - UValue::o.ival = UValue::listToValue(U_ARRAY_VALUE, UValue::sd[UValue::pos--].tails); + UValue::setArray(); } if (UValue::pos != -1) UValue::nextParser(); @@ -2260,7 +2352,8 @@ public: { T item; - U_DUMP("pelement = %p pelement->next = %p pelement->type = (%u,%S)", pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) + U_DUMP("pelement = %p pelement->next = %p pelement->type = (%u,%S)", + pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) UJsonTypeHandler(item).fromJSON(*pelement); @@ -2273,8 +2366,8 @@ public: // by Victor Stewart -# if defined(HAVE_CXX17) && !defined(__clang__) -# include +# if defined(HAVE_CXX17) && !defined(__clang__) +# include template class U_EXPORT UJsonTypeHandler > : public UJsonTypeHandler_Base { public: @@ -2333,6 +2426,6 @@ public: } } }; -# endif +# endif #endif #endif diff --git a/include/ulib/serialize/flatbuffers.h b/include/ulib/serialize/flatbuffers.h new file mode 100644 index 00000000..f7274f85 --- /dev/null +++ b/include/ulib/serialize/flatbuffers.h @@ -0,0 +1,3112 @@ +// ============================================================================ +// +// = LIBRARY +// ULib - c++ library +// +// = FILENAME +// flatbuffers.h +// +// = AUTHOR +// Stefano Casazza +// +// ============================================================================ + +#ifndef ULIB_FLAT_BUFFERS_H +#define ULIB_FLAT_BUFFERS_H + +#include + +/** + * @see http://google.github.io/flatbuffers/index.html + * + * All data is accessed over offsets, all scalars are aligned to their own size, and all data is always stored in little endian format. + * Buffers are built front to back, so children are stored before parents, and the root of the data starts at the last byte. + * + * The scalar data is stored with a variable number of bits (8/16/32/64). The current width is always determined by the *parent*, i.e. + * if the scalar sits in a vector, the vector determines the bit width for all elements at once. Selecting the minimum bit width for a + * particular vector is something the encoder does automatically and thus is typically of no concern to the user, though being aware of + * this feature (and not sticking a double in the same vector as a bunch of byte sized elements) is helpful for efficiency. + * + * There is only one kind of offset, and that is an unsigned integer indicating the number of bytes in a negative direction from the + * address of itself (where the offset is stored). The root starts at the end of the buffer. The last uint8_t is the width in bytes of + * the root (normally the parent determines the width, but the root has no parent). The uint8_t before this is the type of the root, and + * the bytes before that are the root value (of the number of bytes specified by the last byte) + * + * Vectors + * + * The representation of the vector is at the core of how UFlatBuffer works (since maps are really just a combination of 2 vectors). + * A vector is governed by a single bit width (supplied by its parent). This includes the size field. For example, a vector that + * stores the integer values `1, 2, 3` is encoded as follows: + * + * uint8_t 3, 1, 2, 3, 4, 4, 4 + * + * The first `3` is the size field, and is placed before the vector (an offset from the parent to this vector points to the first + * element, not the size field, so the size field is effectively at index -1). Since this is an untyped vector `TYPE_VECTOR`, it + * is followed by 3 type bytes (one per element of the vector), which are always following the vector, and are always a uint8_t + * even if the vector is made up of bigger scalars. There are also the Typed Vectors that omit the type bytes. The type is instead + * determined by the vector type supplied by the parent. Typed vectors are only available for a subset of types for which these + * savings can be significant, namely inline signed/unsigned integers (`TYPE_VECTOR_INT` / `TYPE_VECTOR_UINT`), floats (`TYPE_VECTOR_FLOAT`), + * string (`TYPE_VECTOR_STRING`) and bool (`TYPE_VECTOR_BOOL`). Additionally, for scalars, there are fixed length vectors of sizes 2 / 3 / 4 + * that don't store the size (`TYPE_VECTOR_INT2` etc.), for an additional savings in space when storing common vector or color data. + * + * Scalars + * + * UFlatBuffer supports integers (`TYPE_INT` and `TYPE_UINT`) and floats (`TYPE_FLOAT`), available in the bit-widths mentioned above. + * They can be stored both inline and over an offset (`TYPE_INDIRECT_*`). The offset version is useful to encode costly 64bit (or even + * 32bit) quantities into vectors / maps of smaller sizes, and to share / repeat a value multiple times. + * + * Booleans and Nulls + * + * Booleans (`TYPE_BOOL`) and nulls (`TYPE_NULL`) are encoded as inlined unsigned integers. + * + * Maps + * + * A map (`TYPE_MAP`) is like an (untyped) vector, but with 2 prefixes before the size field: + * + * | index | field | + * | ----: | :-------------------------------------------------------| + * | -3 | An offset to the keys vector | + * | -2 | Byte width of the keys vector | + * | -1 | Size (from here on it is compatible with `TYPE_VECTOR`) | + * | 0 | Elements | + * | Size | Types | + * + * Since a map is otherwise the same as a vector, it can be iterated like a vector (which is probably faster than lookup by key). + * The keys vector is a typed vector of strings. The reason the key vector is a seperate structure from the value vector is such that + * to allow it to be treated as its own individual vector in code. An example map { foo: 13, bar: 14 } would be encoded as: + * + * "\003foo\003bar\002\b\005\002\001\002\r\016\004\004\004$\001" + * 0 4 8 9 11 13 14 16 19 + * + * 0 : uint8_t 3, 'f', 'o', 'o' + * 4 : uint8_t 3, 'b', 'a', 'r' + * 8 : uint8_t 2 // key vector of size 2 + * <-------------------------------------> key vector offset points here + * 9 : uint8_t 8, 5 // offsets to foo_key and bar_key + * 11: uint8_t 2, 1 // offset to key vector, and its byte width + * 13: uint8_t 2 // value vector of size + * <-------------------------------------> value vector offset points here + * 14: uint8_t 13, 14 // values + * 16: uint8_t 4, 4 // types + * 19: uint8_t 40 // root type + * + * The root + * + * The root starts at the end of the buffer. The last uint8_t is the width in bytes of the root (normally the parent determines + * the width, but the root has no parent). The uint8_t before this is the type of the root, and the bytes before that are the + * root value (of the number of bytes specified by the last byte). So for example, the integer value `13` as root would be: + * + * uint8_t 13, 4, 1 // root value, type and byte width + */ + +class UFlatBuffer; + +template class UFlatBufferTypeHandler; + +class U_NO_EXPORT UFlatBufferValue { +public: + + /** + * A type byte is made up of 2 components: + * + * 2 lower bits representing the bit-width of the child (8, 16, 32, 64). + * This is only used if the child is accessed over an offset, such as a child vector. It is ignored for inline types + */ + + enum BitWidth { + BIT_WIDTH_8 = 0, + BIT_WIDTH_16 = 1, + BIT_WIDTH_32 = 2, + BIT_WIDTH_64 = 3 + }; + + /** + * 6 bits representing the actual type + * + * for example 4 (100) means 8 bit child (value 0, unused, since the value is in-line), type `TYPE_INT` (value 1) + */ + + enum Type { + TYPE_NULL = 0, + TYPE_INT = 1, + TYPE_UINT = 2, + TYPE_FLOAT = 3, + TYPE_BOOL = 4, + // Types above stored inline, types below store an offset + TYPE_STRING = 5, + TYPE_INDIRECT_INT = 6, + TYPE_INDIRECT_UINT = 7, + TYPE_INDIRECT_FLOAT = 8, + TYPE_MAP = 9, + TYPE_VECTOR = 10, // Untyped + TYPE_VECTOR_INT = 11, // Typed any size (stores no type table) + TYPE_VECTOR_UINT = 12, + TYPE_VECTOR_FLOAT = 13, + TYPE_VECTOR_BOOL = 14, // To Allow the same type of conversion of type to vector type + TYPE_VECTOR_STRING = 15, + TYPE_VECTOR_INT2 = 16, // Typed tuple (no type table, no size field) + TYPE_VECTOR_UINT2 = 17, + TYPE_VECTOR_FLOAT2 = 18, + TYPE_VECTOR_INT3 = 19, // Typed triple (no type table, no size field) + TYPE_VECTOR_UINT3 = 20, + TYPE_VECTOR_FLOAT3 = 21, + TYPE_VECTOR_INT4 = 22, // Typed quad (no type table, no size field) + TYPE_VECTOR_UINT4 = 23, + TYPE_VECTOR_FLOAT4 = 24 + }; + + static uint32_t size() { return sizeof(double)+(sizeof(uint8_t)*2); } + +protected: + union { uint32_t l_; int64_t i_; uint64_t u_; double f_; }; + uint8_t type_, min_bit_width_; // For scalars: of itself, for vector: of its elements, for string: length + + void reset() + { + U_TRACE_NO_PARAM(0, "UFlatBufferValue::reset()") + + u_ = 0ULL; + type_ = TYPE_NULL; + min_bit_width_ = BIT_WIDTH_8; + } + + void set(uint64_t u = 0ULL, uint8_t type = TYPE_NULL, uint8_t min_bit_width = BIT_WIDTH_8) + { + U_TRACE(0, "UFlatBufferValue::set(%llu,%u,%u)", u, type, min_bit_width) + + u_ = u; + type_ = type; + min_bit_width_ = min_bit_width; + } + + void set(float f) + { + U_TRACE(0, "UFlatBufferValue::set(%g)", f) + + f_ = f; + type_ = TYPE_FLOAT; + min_bit_width_ = BIT_WIDTH_32; + } + + void set(double f) + { + U_TRACE(0, "UFlatBufferValue::set(%g)", f) + + f_ = f; + type_ = TYPE_FLOAT; + min_bit_width_ = WidthF(f); + } + + uint8_t StoredWidth(uint8_t parent_bit_width) const + { + U_TRACE(0, "UFlatBufferValue::StoredWidth(%u)", parent_bit_width) + + if (IsInline(type_) && + min_bit_width_ < parent_bit_width) + { + U_RETURN(parent_bit_width); + } + + U_RETURN(min_bit_width_); + } + + uint8_t StoredPackedType(uint8_t parent_bit_width) const + { + U_TRACE(0, "UFlatBufferValue::StoredPackedType(%u)", parent_bit_width) + + uint8_t bit_width = PackedType(StoredWidth(parent_bit_width), type_); + + U_RETURN(bit_width); + } + + __pure uint8_t ElemWidth(uint32_t buf_size, uint32_t elem_index) const + { + U_TRACE(0, "UFlatBufferValue::ElemWidth(%u,%u)", buf_size, elem_index) + + if (IsInline(type_)) U_RETURN(min_bit_width_); + + // We have an absolute offset, but want to store a relative offset elem_index elements beyond + // the current buffer end. Since whether the relative offset fits in a certain byte_width depends + // on the size of the elements before it (and their alignment), we have to test for each size in turn + + uint8_t bit_width; + uint32_t offset_loc, offset; + + for (uint8_t byte_width = 1; byte_width <= sizeof(uint32_t); byte_width *= 2) + { + // Where are we going to write this offset? + + offset_loc = buf_size + PaddingBytes(buf_size, byte_width) + elem_index * byte_width; + + // Compute relative offset + + offset = offset_loc - l_; + + // Does it fit? + + bit_width = WidthL(offset); + + U_INTERNAL_DUMP("bit_width = %u byte_width = %u offset = %u offset_loc = %u", bit_width, byte_width, offset, offset_loc) + + if ((1U << bit_width) == byte_width) U_RETURN(bit_width); + } + + U_INTERNAL_ASSERT(false) // Must match one of the sizes above + + U_RETURN(BIT_WIDTH_64); + } + + static uint8_t WidthB(uint32_t byte_width) + { + U_TRACE(0, "UFlatBufferValue::WidthB(%u)", byte_width) + + switch (byte_width) + { + case 1: U_RETURN(BIT_WIDTH_8); + case 2: U_RETURN(BIT_WIDTH_16); + case 4: U_RETURN(BIT_WIDTH_32); + case 8: U_RETURN(BIT_WIDTH_64); + + default: U_INTERNAL_ASSERT(false); + } + + U_RETURN(BIT_WIDTH_64); + } + + static uint8_t WidthL(uint32_t u) + { + U_TRACE(0, "UFlatBufferValue::WidthL(%u)", u) + + if ((u & ~((1U << 8) - 1U)) == 0) U_RETURN(BIT_WIDTH_8); + if ((u & ~((1U << 16) - 1U)) == 0) U_RETURN(BIT_WIDTH_16); + + U_RETURN(BIT_WIDTH_32); + } + + static uint8_t WidthU(uint64_t u) + { + U_TRACE(0, "UFlatBufferValue::WidthU(%llu)", u) + + if ((u & ~((1ULL << 8) - 1ULL)) == 0) U_RETURN(BIT_WIDTH_8); + if ((u & ~((1ULL << 16) - 1ULL)) == 0) U_RETURN(BIT_WIDTH_16); + if ((u & ~((1ULL << 32) - 1ULL)) == 0) U_RETURN(BIT_WIDTH_32); + + U_RETURN(BIT_WIDTH_64); + } + + static uint8_t WidthI(int64_t i) + { + U_TRACE(0, "UFlatBufferValue::WidthI(%lld)", i) + + U_INTERNAL_ASSERT_MINOR(i, 0) + + return WidthU(-i); + } + + static uint8_t WidthF(double f) + { + U_TRACE(0, "UFlatBufferValue::WidthF(%g)", f) + + U_RETURN((double)((float)f) == f ? BIT_WIDTH_32 : BIT_WIDTH_64); + } + + static bool IsInline(uint8_t t) + { + U_TRACE(0, "UFlatBufferValue::IsInline(%u)", t) + + if (t <= TYPE_BOOL) U_RETURN(true); + + U_RETURN(false); + } + + static uint8_t PackedType(uint8_t bit_width, uint8_t type) + { + U_TRACE(0, "UFlatBufferValue::PackedType(%u,%u)", bit_width, type) + + return (bit_width | (type << 2)); + } + + // Computes how many bytes you'd have to pad to be able to write an + // "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in memory) + + static uint32_t PaddingBytes(uint32_t buf_size, uint32_t scalar_size) + { + U_TRACE(0, "UFlatBufferValue::PaddingBytes(%u,%u)", buf_size, scalar_size) + + U_RETURN(((~buf_size)+1) & (scalar_size-1)); + } + +private: + friend class UFlatBuffer; + + U_DISALLOW_COPY_AND_ASSIGN(UFlatBufferValue) +}; + +class U_EXPORT UFlatBuffer { +public: + + // Check for memory error + U_MEMORY_TEST + + // Allocator e Deallocator + U_MEMORY_ALLOCATOR + U_MEMORY_DEALLOCATOR + + UFlatBuffer() + { + U_TRACE_REGISTER_OBJECT(0, UFlatBuffer, "", 0) + } + + ~UFlatBuffer() + { + U_TRACE_UNREGISTER_OBJECT(0, UFlatBuffer) + } + + // SERVICES + + uint8_t GetType() const { return type_; } + + static bool IsBool(uint8_t type) { return type == UFlatBufferValue::TYPE_BOOL; } + static bool IsInt(uint8_t type) { return (type == UFlatBufferValue::TYPE_INT || type == UFlatBufferValue::TYPE_INDIRECT_INT); } + static bool IsUInt(uint8_t type) { return (type == UFlatBufferValue::TYPE_UINT || type == UFlatBufferValue::TYPE_INDIRECT_UINT); } + static bool IsIntOrUint(uint8_t type) { return (IsInt(type) || IsUInt(type)); } + static bool IsFloat(uint8_t type) { return (type == UFlatBufferValue::TYPE_FLOAT || type == UFlatBufferValue::TYPE_INDIRECT_FLOAT); } + static bool IsVector(uint8_t type) { return type == UFlatBufferValue::TYPE_VECTOR; } + static bool IsNumeric(uint8_t type) { return (IsIntOrUint(type) || IsFloat(type)); } + static bool IsScalar(uint8_t type) { return (IsNumeric(type) || IsBool(type)); } + + bool IsNull() const { return type_ == UFlatBufferValue::TYPE_NULL; } + bool IsString() const { return type_ == UFlatBufferValue::TYPE_STRING; } + bool IsMap() const { return type_ == UFlatBufferValue::TYPE_MAP; } + bool IsBool() const { return IsBool(type_); } + bool IsInt() const { return IsInt(type_); } + bool IsUInt() const { return IsUInt(type_); } + bool IsIntOrUint() const { return IsIntOrUint(type_); } + bool IsFloat() const { return IsFloat(type_); } + bool IsNumeric() const { return IsNumeric(type_); } + bool IsVector() const { return IsVector(type_); } // Maps can be viewed as vectors too + + bool IsTypedVector() const { return (type_ >= UFlatBufferValue::TYPE_VECTOR_INT && type_ <= UFlatBufferValue::TYPE_VECTOR_STRING); } + bool IsFixedTypedVector() const { return (type_ >= UFlatBufferValue::TYPE_VECTOR_INT2 && type_ <= UFlatBufferValue::TYPE_VECTOR_FLOAT4); } + + // All value constructing functions below have two versions: one that takes a key + // (for placement inside a map) and one that doesn't (for inside vectors and elsewhere) + + static void Null() { pushOnStack(); } + static void Bool(bool b) { pushOnStack((uint64_t)b, UFlatBufferValue::TYPE_BOOL, UFlatBufferValue::BIT_WIDTH_8); } + static void Int( int64_t i) { pushOnStack(-i, UFlatBufferValue::TYPE_INT, UFlatBufferValue::WidthI(i)); } + static void UInt(uint64_t u) { pushOnStack(u, UFlatBufferValue::TYPE_UINT, UFlatBufferValue::WidthU(u)); } + static void Float(float f) { pushOnStack(f); } + static void Double(double d) { pushOnStack(d); } + + static void setNumber(int64_t l) + { + U_TRACE(0, "UFlatBuffer::setNumber(%lld)", l) + + if (l < 0) Int(l); + else UInt(l); + } + + void IndirectInt( int64_t i) { PushIndirect((uint64_t)i, UFlatBufferValue::TYPE_INDIRECT_INT, UFlatBufferValue::WidthU((uint64_t)i)); } + void IndirectUInt(uint64_t u) { PushIndirect(u, UFlatBufferValue::TYPE_INDIRECT_UINT, UFlatBufferValue::WidthU(u)); } + void IndirectFloat(float f) { PushIndirectFloat(f); } + void IndirectDouble(double f) { PushIndirect(f, UFlatBufferValue::TYPE_INDIRECT_FLOAT, UFlatBufferValue::WidthF(f)); } + + void String(const char* str, uint32_t len) { CreateString(str, len); } + + void Null( const char* key, uint32_t len) { Key(key, len); Null(); } + void Bool( const char* key, uint32_t len, bool b) { Key(key, len); Bool(b); } + void Int( const char* key, uint32_t len, int64_t i) { Key(key, len); Int(i); } + void UInt( const char* key, uint32_t len, uint64_t u) { Key(key, len); UInt(u); } + void Float( const char* key, uint32_t len, float f) { Key(key, len); Float(f); } + void Double(const char* key, uint32_t len, double d) { Key(key, len); Double(d); } + + void IndirectInt( const char* key, uint32_t len, int64_t i) { Key(key, len); IndirectInt(i); } + void IndirectUInt( const char* key, uint32_t len, uint64_t u) { Key(key, len); IndirectUInt(u); } + void IndirectFloat( const char* key, uint32_t len, float f) { Key(key, len); IndirectFloat(f); } + void IndirectDouble(const char* key, uint32_t len, double d) { Key(key, len); IndirectDouble(d); } + + void String(const char* key, uint32_t len1, const char* str, uint32_t len2) { Key(key, len1); CreateString(str, len2); } + + // Overloaded Add that tries to call the correct function above + + static void Add() { Null(); } + static void Add(bool b) { Bool(b); } + static void Add( int64_t i) { Int(i); } + static void Add(uint64_t u) { UInt(u); } + static void Add(float f) { Float(f); } + static void Add(double d) { Double(d); } + + void Add(const char* str, uint32_t len) { CreateString(str, len); } + + void Key(const char* key, uint32_t len) { CreateString(key, len); } + + void Add(const char* key, uint32_t len, bool b) { Key(key, len); Bool(b); } + void Add(const char* key, uint32_t len, int64_t i) { Key(key, len); Int(i); } + void Add(const char* key, uint32_t len, uint64_t u) { Key(key, len); UInt(u); } + void Add(const char* key, uint32_t len, float f) { Key(key, len); Float(f); } + void Add(const char* key, uint32_t len, double d) { Key(key, len); Double(d); } + + void Add(const char* key, uint32_t len1, const char* str, uint32_t len2) { Key(key, len1); CreateString(str, len2); } + + static uint32_t StartVector() + { + U_TRACE_NO_PARAM(0, "UFlatBuffer::StartVector()") + + U_RETURN(stack_idx); + } + + uint32_t StartVector(const char* key, uint32_t len) + { + U_TRACE(0, "UFlatBuffer::StartVector(%.*S,%u)", len, key, len) + + Key(key, len); + + U_RETURN(stack_idx); + } + + static uint32_t StartMap() + { + U_TRACE_NO_PARAM(0, "UFlatBuffer::StartMap()") + + U_RETURN(stack_idx); + } + + uint32_t StartMap(const char* key, uint32_t len) + { + U_TRACE(0, "UFlatBuffer::StartMap(%.*S,%u)", len, key, len) + + uint32_t start = stack_idx; + + Key(key, len); + + U_RETURN(start); + } + + void EndMap( uint32_t start); + void EndVector(uint32_t start, bool typed = true, bool fixed = false) + { + U_TRACE(0, "UFlatBuffer::EndVector(%u,%b,%b)", start, typed, fixed) + + CreateVector(start, stack_idx-start, 1, typed, fixed, U_NULLPTR); + } + + template void TypedVector(const T* elems, uint32_t len) + { + U_TRACE(0, "UFlatBuffer::TypedVector(%p,%u)", elems, len) + + uint32_t start = StartVector(); + + for (uint32_t i = 0; i < len; ++i) Add(elems[i]); + + EndVector(start); + } + + template void TypedVector(const char* key, uint32_t klen, const T* elems, uint32_t len) + { + U_TRACE(0, "UFlatBuffer::TypedVector(%.*S,%u,%p,%u)", klen, key, klen, elems, len) + + uint32_t start = StartVector(key, klen); + + for (uint32_t i = 0; i < len; ++i) Add(elems[i]); + + EndVector(start); + } + + template void FixedTypedVector(const T* elems, uint32_t len, uint8_t vector_type = UFlatBufferValue::TYPE_UINT) // only scalar values + { + U_TRACE(0, "UFlatBuffer::FixedTypedVector(%p,%u,%u)", elems, len, vector_type) + + U_INTERNAL_ASSERT_RANGE(2, len, 4) // We only support a few fixed vector lengths. Anything bigger use a regular typed vector + + ScalarVector(elems, len, vector_type, true); + } + + template void FixedTypedVector(const char* key, uint32_t klen, const T* elems, uint32_t len, uint8_t vector_type = UFlatBufferValue::TYPE_UINT) // only scalar values + { + U_TRACE(0, "UFlatBuffer::FixedTypedVector(%.*S,%u,%p,%u,%u)", klen, key, klen, elems, len, vector_type) + + U_INTERNAL_ASSERT_RANGE(2, len, 4) // We only support a few fixed vector lengths. Anything bigger use a regular typed vector + + Key(key, klen); + + ScalarVector(elems, len, vector_type, true); + } + + template void ScalarVector(const T* elems, uint32_t len, uint8_t vector_type = UFlatBufferValue::TYPE_UINT, bool fixed = true) + { + U_TRACE(0, "UFlatBuffer::ScalarVector(%p,%u,%u,%b)", elems, len, vector_type, fixed) + + U_INTERNAL_ASSERT(IsScalar(vector_type)) + + uint8_t byte_width = sizeof(T), bit_width = UFlatBufferValue::WidthB(byte_width); + + // If you get this assert, you're trying to write a vector with a size field that is bigger than the scalars + // you're trying to write (e.g. a byte vector > 255 elements). For such types, write a "string" instead + + U_INTERNAL_ASSERT(UFlatBufferValue::WidthU(len) <= bit_width) + + if (fixed == false) WriteScalar(len, byte_width); +# ifdef DEBUG + else + { + U_INTERNAL_ASSERT(IsNumeric(vector_type)) + } +# endif + + uint32_t vloc = buffer_idx; + + for (uint32_t i = 0; i < len; ++i) WriteScalar(elems[i], byte_width); + + pushOnStack(vloc, ToTypedVector(vector_type, fixed ? len : 0), bit_width); + } + + template void Vector(F f, bool typed = false, bool fixed = false) + { + U_TRACE(0, "UFlatBuffer::Vector(%p,%b,%b)", f, typed, fixed) + + uint32_t start = StartVector(); + + f(); + + EndVector(start, typed, fixed); + } + + template void Vector(const char* key, uint32_t len, F f, bool typed = false, bool fixed = false) + { + U_TRACE(0, "UFlatBuffer::Vector(%.*S,%u,%p,%b,%b)", len, key, len, f, typed, fixed) + + uint32_t start = StartVector(key, len); + + f(); + + EndVector(start, typed, fixed); + } + + template void Map(F f) + { + U_TRACE(0, "UFlatBuffer::Map(%p)", f) + + uint32_t start = StartMap(); + + f(); + + EndMap(start); + } + + template void Map(const char* key, uint32_t len, F f) + { + U_TRACE(0, "UFlatBuffer::Map(%.*S,%u,%p)", len, key, len, f) + + uint32_t start = StartMap(key, len); + + f(); + + EndMap(start); + } + + // manage object <=> FlatBuffer representation + + template void toFlatBuffer(UFlatBufferTypeHandler member) + { + U_TRACE(0, "UFlatBuffer::toFlatBuffer(%p)", &member) + + member.toFlatBuffer(*this); + } + + template void toFlatBuffer(const UString& key, UFlatBufferTypeHandler member) + { + U_TRACE(0, "UFlatBuffer::toFlatBuffer(%V, %p)", key.rep, &member) + + Key(U_STRING_TO_PARAM(key)); + + member.toFlatBuffer(*this); + } + + template void fromFlatBuffer(uint32_t i, UFlatBufferTypeHandler member) + { + U_TRACE(0, "UFlatBuffer::fromFlatBuffer(%u,%p)", i, &member) + + UFlatBuffer fb; + + AsVectorGet(i, fb); + + member.fromFlatBuffer(fb); + } + + template void toObject(T& obj); + template void fromObject(T& obj); + + // INIT + + static void setStack(uint8_t* ptr, uint32_t len) + { + U_TRACE(0, "UFlatBuffer::setStack(%p,%u)", ptr, len) + + stack_str = ptr; + stack_max = len / UFlatBufferValue::size(); + } + + static void setBuffer(uint8_t* ptr, uint32_t len) + { + U_TRACE(0, "UFlatBuffer::setBuffer(%p,%u)", ptr, len) + + buffer_str = ptr; + buffer_max = len; + } + + UString getResult() const { return UString(buffer_str, buffer_idx); } + uint8_t* getPointer() const { return buffer_str+buffer_idx; } + uint32_t getBufferSize() const { return buffer_idx; } + + static uint8_t* getStack() { return stack_str; } + static uint8_t* getBuffer() { return buffer_str; } + static uint32_t getStackMax() { return stack_max * UFlatBufferValue::size(); } + static uint32_t getBufferMax() { return buffer_max; } + + // BUILD + + void StartBuild() + { + U_TRACE_NO_PARAM(0, "UFlatBuffer::StartBuild()") + + U_INTERNAL_ASSERT_POINTER(stack_str) + U_INTERNAL_ASSERT_POINTER(buffer_str) + + // Reset all state so we can re-use the buffers + + setStackPointer(stack_idx = buffer_idx = 0); + + pvalue->reset(); + + data_ = U_NULLPTR; + type_ = UFlatBufferValue::TYPE_NULL; + byte_width_ = + parent_width_ = UFlatBufferValue::BIT_WIDTH_8; + } + + uint32_t EndBuild() + { + U_TRACE_NO_PARAM(0, "UFlatBuffer::EndBuild()") + + // If you hit this assert, you likely have objects that were never included in a parent. + // You need to have exactly one root to finish a buffer. Check your Start/End calls are + // matched, and all objects are inside some other object + + U_INTERNAL_ASSERT_EQUALS(stack_idx, 1) + + U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) + + U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) + + uint8_t byte_width = Align(((UFlatBufferValue*)stack_str)->ElemWidth(buffer_idx, 0)); + + WriteAny(byte_width); // Write root value + + WriteScalar8(((UFlatBufferValue*)stack_str)->StoredPackedType(UFlatBufferValue::BIT_WIDTH_8)); // Write root type + + WriteScalar8(byte_width); // Write root size. Normally determined by parent, but root has no parent :) + + U_INTERNAL_DUMP("buffer(%u) = %#.*S", buffer_idx, buffer_idx, buffer_str) + + U_RETURN(buffer_idx); + } + + template uint32_t encode(F f) + { + U_TRACE(0, "UFlatBuffer::encode(%p)", f) + + StartBuild(); + + f(); + + return EndBuild(); + } + + template uint32_t encodeVector(F f, bool typed = false, bool fixed = false) + { + U_TRACE(0, "UFlatBuffer::encodeVector(%p,%b,%b)", f, typed, fixed) + + StartBuild(); + + (void) StartVector(); + + f(); + + EndVector(0, typed, fixed); + + return EndBuild(); + } + + template uint32_t encodeMap(F f) + { + U_TRACE(0, "UFlatBuffer::encodeMap(%p)", f) + + StartBuild(); + + (void) StartMap(); + + f(); + + EndMap(0); + + return EndBuild(); + } + + void AddVectorEmpty() + { + U_TRACE_NO_PARAM(0, "UFlatBuffer::AddVectorEmpty()") + + buffer_str[buffer_idx++] = 0; + + U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) + + U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) + + pushOnStack(buffer_idx, UFlatBufferValue::TYPE_VECTOR_BOOL, UFlatBufferValue::BIT_WIDTH_8); + } + + void AddMapEmpty() + { + U_TRACE_NO_PARAM(0, "UFlatBuffer::AddMapEmpty()") + + u_put_unalignedp32(buffer_str+buffer_idx, U_MULTICHAR_CONSTANT32(0,1,1,0)); + + pushOnStack((buffer_idx += 4), UFlatBufferValue::TYPE_MAP, UFlatBufferValue::BIT_WIDTH_8); + + U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) + + U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) + } + + // PARSE + + void setRoot(const uint8_t* ptr, uint32_t len) // See EndBuild() below for the serialization counterpart of this + { + U_TRACE(0, "UFlatBuffer::setRoot(%p,%u)", ptr, len) + + data_ = (buffer_str = (uint8_t*)ptr) + len; // The root starts at the end of the buffer, so we parse backwards from there + + parent_width_ = *--data_; + + setTypeAndWidth(*--data_); + + data_ -= parent_width_; // The root data item + + U_DUMP("type_ = (%u,%S) byte_width_ = %u parent_width_ = %u data_(%u) = %#.*S", type_, getTypeDescription(type_), byte_width_, parent_width_, 2+byte_width_, 2+byte_width_, data_) + } + + void setRoot() { setRoot(buffer_str, buffer_idx); } + + bool AsBool() const { return AsBool(data_); } + int64_t AsInt64() const { return AsInt64(data_); } + uint64_t AsUInt64() const { return AsUInt64(data_); } + float AsFloat() const { return AsFloat(data_); } + double AsDouble() const { return AsDouble(data_); } + UString AsString() const { return AsString(data_); } + + int8_t AsInt8() const { return (int8_t) AsInt64(data_); } + int16_t AsInt16() const { return (int16_t)AsInt64(data_); } + int32_t AsInt32() const { return (int32_t)AsInt64(data_); } + + int64_t AsIndirectInt64() const { return AsIndirectInt64(data_); } + uint64_t AsIndirectUInt64() const { return AsIndirectUInt64(data_); } + float AsIndirectFloat() const { return AsIndirectFloat(data_); } + double AsIndirectDouble() const { return AsIndirectDouble(data_); } + + int8_t AsIndirectInt8() const { return (int8_t) AsIndirectInt64(data_); } + int16_t AsIndirectInt16() const { return (int16_t)AsIndirectInt64(data_); } + int32_t AsIndirectInt32() const { return (int32_t)AsIndirectInt64(data_); } + + int64_t AsNumber() const + { + U_TRACE_NO_PARAM(0, "UFlatBuffer::AsNumber()") + + if (type_ == UFlatBufferValue::TYPE_INT) return AsInt64(); + + U_INTERNAL_ASSERT_EQUALS(type_, UFlatBufferValue::TYPE_UINT) + + return AsUInt64(); + } + + int64_t AsIndirectNumber() const + { + U_TRACE_NO_PARAM(0, "UFlatBuffer::AsIndirectNumber()") + + if (type_ == UFlatBufferValue::TYPE_INDIRECT_INT) return AsIndirectInt64(); + + U_INTERNAL_ASSERT_EQUALS(type_, UFlatBufferValue::TYPE_INDIRECT_UINT) + + return AsIndirectUInt64(); + } + + uint32_t GetSize() const + { + U_TRACE_NO_PARAM(0, "UFlatBuffer::GetSize()") + + U_RETURN(buffer_idx); + } + + // VECTOR + + void AsVector(UFlatBuffer& fb) const { AsVector(data_, fb); } + void AsTypedVector(UFlatBuffer& fb) const { AsTypedVector(data_, fb); } + void AsFixedTypedVector(UFlatBuffer& fb) const { AsFixedTypedVector(data_, fb); } + + template T AsVectorGet(uint32_t i) + { + U_TRACE(0, "UFlatBuffer::AsVectorGet(%u)", i) + + T value = Get(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_VECTOR; + + return value; + } + + template T AsVectorGetIndirect(uint32_t i) + { + U_TRACE(0, "UFlatBuffer::AsVectorGetIndirect(%u)", i) + + T value = GetIndirect(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_VECTOR; + + return value; + } + + template T AsTypedOrFixedVectorGet(uint32_t i) + { + U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGet(%u)", i) + + return Get(AsTypedOrFixedVectorSetIndex(i)); + } + + template T AsTypedOrFixedVectorGetIndirect(uint32_t i) + { + U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGetIndirect(%u)", i) + + return GetIndirect(AsTypedOrFixedVectorSetIndex(i)); + } + + template bool AsVectorIsEqual(const T* elems, uint32_t len) + { + U_TRACE(0, "UFlatBuffer::AsVectorIsEqual(%p,%u)", elems, len) + + for (uint32_t i = 0; i < len; ++i) + { + if (AsVectorGet(i) != elems[i]) U_RETURN(false); + } + + U_RETURN(true); + } + + template bool AsTypedOrFixedVectorIsEqual(const T* elems, uint32_t len) + { + U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorIsEqual(%p,%u)", elems, len) + + for (uint32_t i = 0; i < len; ++i) + { + if (AsTypedOrFixedVectorGet(i) != elems[i]) U_RETURN(false); + } + + U_RETURN(true); + } + + // MAP + + void AsMap(UFlatBuffer& fb) const { AsMap(data_, fb); } + void AsMapGetKeys(UFlatBuffer& fb) const { AsMapGetKeys(data_, fb); } + void AsMapGetValues(UFlatBuffer& fb) const { AsMapGetValues(data_, fb); } + + uint32_t AsMapGetKeys(UVector& members) const; + + template T AsMapGet(uint32_t i) + { + U_TRACE(0, "UFlatBuffer::AsMapGet(%u)", i) + + U_INTERNAL_ASSERT(IsMap()) + + T value = Get(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_MAP; + + return value; + } + + template T AsMapGetIndirect(uint32_t i) + { + U_TRACE(0, "UFlatBuffer::AsMapGetIndirect(%u)", i) + + U_INTERNAL_ASSERT(IsMap()) + + T value = GetIndirect(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_MAP; + + return value; + } + + template T AsMapGet(const char* key, uint32_t len) + { + U_TRACE(0, "UFlatBuffer::AsMapGet(%.*S,%u)", len, key, len) + + U_INTERNAL_ASSERT(IsMap()) + + T value = Get(AsMapSetIndex(key, len)); + + type_ = UFlatBufferValue::TYPE_MAP; + + return value; + } + + template T AsMapGetIndirect(const char* key, uint32_t len) + { + U_TRACE(0, "UFlatBuffer::AsMapGetIndirect(%.*S,%u)", len, key, len) + + U_INTERNAL_ASSERT(IsMap()) + + T value = GetIndirect(AsMapSetIndex(key, len)); + + type_ = UFlatBufferValue::TYPE_MAP; + + return value; + } + + // VECTOR <=> MAP + + void AsVectorGetVector(uint32_t i, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsVectorGetVector(%u,%p)", i, &fb) + + U_INTERNAL_ASSERT(IsVector()) + + AsVector(AsVectorSetIndex(i), fb); + + byte_width_ = parent_width_; + + type_ = UFlatBufferValue::TYPE_VECTOR; + } + + void AsVectorGetTypedVector(uint32_t i, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsVectorGetTypedVector(%u,%p)", i, &fb) + + U_INTERNAL_ASSERT(IsVector()) + + AsTypedVector(AsVectorSetIndex(i), fb); + + byte_width_ = parent_width_; + + type_ = UFlatBufferValue::TYPE_VECTOR; + } + + void AsVectorGetFixedTypedVector(uint32_t i, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsVectorGetFixedTypedVector(%u,%p)", i, &fb) + + U_INTERNAL_ASSERT(IsVector()) + + AsFixedTypedVector(AsVectorSetIndex(i), fb); + + byte_width_ = parent_width_; + + type_ = UFlatBufferValue::TYPE_VECTOR; + } + + void AsVectorGetMap(uint32_t i, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsVectorGetMap(%u,%p)", i, &fb) + + U_INTERNAL_ASSERT(IsVector()) + + AsMap(AsVectorSetIndex(i), fb); + + byte_width_ = parent_width_; + + type_ = UFlatBufferValue::TYPE_VECTOR; + } + + void AsTypedOrFixedVectorGetMap(uint32_t i, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGetMap(%u,%p)", i, &fb) + + U_INTERNAL_ASSERT(IsTypedVector() || IsTypedVectorElementType()) + + AsMap(AsVectorSetIndex(i), fb); + + byte_width_ = parent_width_; + } + + void AsMapGetVector(uint32_t i, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsMapGetVector(%u,%p)", i, &fb) + + U_INTERNAL_ASSERT(IsMap()) + + AsVector(AsVectorSetIndex(i), fb); + + byte_width_ = parent_width_; + + type_ = UFlatBufferValue::TYPE_MAP; + } + + void AsMapGetVector(const char* key, uint32_t len, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsMapGetVector(%.*S,%u,%p)", len, key, len, &fb) + + U_INTERNAL_ASSERT(IsMap()) + + AsVector(AsMapSetIndex(key, len), fb); + + byte_width_ = parent_width_; + + type_ = UFlatBufferValue::TYPE_MAP; + } + + void AsMapGetTypedVector(uint32_t i, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsMapGetTypedVector(%u,%p)", i, &fb) + + U_INTERNAL_ASSERT(IsMap()) + + AsTypedVector(AsVectorSetIndex(i), fb); + + byte_width_ = parent_width_; + + type_ = UFlatBufferValue::TYPE_MAP; + } + + void AsMapGetTypedVector(const char* key, uint32_t len, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsMapGetTypedVector(%.*S,%u,%p)", len, key, len, &fb) + + U_INTERNAL_ASSERT(IsMap()) + + AsTypedVector(AsMapSetIndex(key, len), fb); + + byte_width_ = parent_width_; + + type_ = UFlatBufferValue::TYPE_MAP; + } + + void AsMapGetFixedTypedVector(uint32_t i, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsMapGetFixedTypedVector(%u,%p)", i, &fb) + + U_INTERNAL_ASSERT(IsMap()) + + AsFixedTypedVector(AsVectorSetIndex(i), fb); + + byte_width_ = parent_width_; + + type_ = UFlatBufferValue::TYPE_MAP; + } + + void AsMapGetFixedTypedVector(const char* key, uint32_t len, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsMapGetFixedTypedVector(%.*S,%u,%p)", len, key, len, &fb) + + U_INTERNAL_ASSERT(IsMap()) + + AsFixedTypedVector(AsMapSetIndex(key, len), fb); + + byte_width_ = parent_width_; + + type_ = UFlatBufferValue::TYPE_MAP; + } + + void AsMapGetMap(uint32_t i, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsMapGetMap(%u,%p)", i, &fb) + + U_INTERNAL_ASSERT(IsMap()) + + AsMap(AsVectorSetIndex(i), fb); + + byte_width_ = parent_width_; + + type_ = UFlatBufferValue::TYPE_MAP; + } + + void AsMapGetMap(const char* key, uint32_t len, UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBuffer::AsMapGetMap(%.*S,%u,%p)", len, key, len, &fb) + + U_INTERNAL_ASSERT(IsMap()) + + AsMap(AsMapSetIndex(key, len), fb); + + byte_width_ = parent_width_; + + type_ = UFlatBufferValue::TYPE_MAP; + } + +#ifdef DEBUG + const char* dump(bool reset) const; + + static const char* getTypeDescription(uint8_t type); +#else + static const char* getTypeDescription(uint8_t) { return ""; } +#endif + +protected: + uint8_t* data_; + uint32_t buffer_idx; + uint8_t type_, byte_width_, parent_width_; + + static uint8_t* stack_str; + static uint8_t* buffer_str; + static uint32_t stack_idx, stack_max, buffer_max; + + static UFlatBufferValue* pkeys; + static UFlatBufferValue* pvalue; + + static void setStackPointer(uint32_t idx) + { + U_TRACE(0, "UFlatBuffer::setStackPointer(%u)", idx) + + U_INTERNAL_DUMP("stack_idx = %u stack_max = %u", stack_idx, stack_max) + + U_INTERNAL_ASSERT_MINOR(idx, stack_max) + + pvalue = (UFlatBufferValue*)(stack_str + (idx * UFlatBufferValue::size())); + } + +#ifdef DEBUG + static void checkStackPointer() + { + U_TRACE_NO_PARAM(0, "UFlatBuffer::checkStackPointer()") + + U_INTERNAL_DUMP("idx = %u stack_max = %u", ((uint8_t*)pvalue - stack_str) / UFlatBufferValue::size(), stack_max) + + U_INTERNAL_ASSERT_MINOR(((uint8_t*)pvalue - stack_str) / UFlatBufferValue::size(), stack_max) + } +#endif + + static void nextStackPointer() + { + U_TRACE_NO_PARAM(0+256, "UFlatBuffer::nextStackPointer()") + + pvalue = (UFlatBufferValue*)((uint8_t*)pvalue + UFlatBufferValue::size()); + +# ifdef DEBUG + checkStackPointer(); +# endif + } + + static void next2StackPointer() + { + U_TRACE_NO_PARAM(0+256, "UFlatBuffer::next2StackPointer()") + + pvalue = (UFlatBufferValue*)((uint8_t*)pvalue + (UFlatBufferValue::size()*2)); + +# ifdef DEBUG + checkStackPointer(); +# endif + } + + static void pushOnStack(uint64_t u = 0ULL, uint8_t type = UFlatBufferValue::TYPE_NULL, uint8_t min_bit_width = UFlatBufferValue::BIT_WIDTH_8) + { + U_TRACE(0, "UFlatBuffer::pushOnStack(%llu,%u,%u)", u, type, min_bit_width) + + setStackPointer(stack_idx++); + + pvalue->set(u, type, min_bit_width); + } + + static void pushOnStack(float f) + { + U_TRACE(0, "UFlatBufferValue::pushOnStack(%g)", f) + + setStackPointer(stack_idx++); + + pvalue->set(f); + } + + static void pushOnStack(double f) + { + U_TRACE(0, "UFlatBufferValue::pushOnStack(%g)", f) + + setStackPointer(stack_idx++); + + pvalue->set(f); + } + + static uint8_t GetByteWidth(uint32_t len) + { + U_TRACE(0, "UFlatBuffer::GetByteWidth(%u)", len) + + uint8_t bit_width = UFlatBufferValue::WidthL(len); + + U_RETURN(Align(bit_width)); + } + + void CreateString(const char* data, uint32_t len) + { + U_TRACE(0, "UFlatBuffer::CreateString(%.*S,%u)", len, data, len) + + uint8_t bit_width = UFlatBufferValue::WidthL(len); + + WriteScalar(len, Align(bit_width)); + + uint32_t sloc = buffer_idx; + + WriteBytes(data, len); + + pushOnStack(sloc, UFlatBufferValue::TYPE_STRING, bit_width); + } + + void CreateVector(uint32_t start, uint32_t vec_len, uint32_t step, bool typed, bool fixed, UFlatBufferValue* pval); + + uint8_t ToTypedVectorElementType() const + { + U_TRACE_NO_PARAM(0, "UFlatBuffer::ToTypedVectorElementType()") + + U_INTERNAL_ASSERT(IsTypedVector()) + + U_RETURN(type_ - UFlatBufferValue::TYPE_VECTOR_INT + UFlatBufferValue::TYPE_INT); + } + + uint8_t ToFixedTypedVectorElementType(UFlatBuffer& fb) const + { + U_TRACE(0, "UFlatBuffer::ToFixedTypedVectorElementType(%p)", &fb) + + uint8_t fixed_type = type_ - UFlatBufferValue::TYPE_VECTOR_INT2; + + fb.buffer_idx = (uint8_t)(fixed_type / 3 + 2); // 3 types each, starting from length 2 + + U_RETURN(fixed_type % 3 + UFlatBufferValue::TYPE_INT); + } + + static bool IsTypedVectorElementType(uint8_t t) + { + U_TRACE(0, "UFlatBuffer::IsTypedVectorElementType(%u)", t) + + U_DUMP("t = %S", getTypeDescription(t)) + + if (t >= UFlatBufferValue::TYPE_INT && t <= UFlatBufferValue::TYPE_STRING) U_RETURN(true); + + U_RETURN(false); + } + + static uint8_t ToTypedVector(uint8_t t, uint8_t fixed_len) + { + U_TRACE(0, "UFlatBuffer::ToTypedVector(%u,%u)", t, fixed_len) + + U_INTERNAL_ASSERT(IsVector(t) || IsTypedVectorElementType(t)) + + if (fixed_len == 0) U_RETURN(t - UFlatBufferValue::TYPE_INT + UFlatBufferValue::TYPE_VECTOR_INT); + if (fixed_len == 2) U_RETURN(t - UFlatBufferValue::TYPE_INT + UFlatBufferValue::TYPE_VECTOR_INT2); + if (fixed_len == 3) U_RETURN(t - UFlatBufferValue::TYPE_INT + UFlatBufferValue::TYPE_VECTOR_INT3); + + U_INTERNAL_ASSERT_EQUALS(fixed_len, 4) + + U_RETURN(t - UFlatBufferValue::TYPE_INT + UFlatBufferValue::TYPE_VECTOR_INT4); + } + + bool IsTypedVectorElementType() const { return IsTypedVectorElementType(type_); } + + // WRITE + + void WriteBytes(const void* val, uint32_t len) + { + U_TRACE(0, "UFlatBuffer::WriteBytes(%#.*S,%u)", len, val, len) + + (void) memcpy(getPointer(), val, len); + + buffer_idx += len; + + U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) + + U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) + } + + void WriteScalar8(uint8_t i) + { + U_TRACE(0, "UFlatBuffer::WriteScalar8(%u)", i) + + buffer_str[buffer_idx++] = i; + + U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) + + U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) + } + + void WriteScalar16(uint16_t i) + { + U_TRACE(0, "UFlatBuffer::WriteScalar16(%u)", i) + +# if __BYTE_ORDER == __LITTLE_ENDIAN + u_put_unalignedp16(getPointer(), i); +# else + u_put_unalignedp16(getPointer(), U_BYTESWAP16(i)); +# endif + + buffer_idx += sizeof(uint16_t); + + U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) + + U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) + } + + void WriteScalar32(uint32_t i) + { + U_TRACE(0, "UFlatBuffer::WriteScalar32(%u)", i) + +# if __BYTE_ORDER == __LITTLE_ENDIAN + u_put_unalignedp32(getPointer(), i); +# else + u_put_unalignedp32(getPointer(), U_BYTESWAP32(i)); +# endif + + buffer_idx += sizeof(uint32_t); + + U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) + + U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) + } + + void WriteScalar64(uint64_t i) + { + U_TRACE(0, "UFlatBuffer::WriteScalar64(%llu)", i) + +# if __BYTE_ORDER == __LITTLE_ENDIAN + u_put_unalignedp64(getPointer(), i); +# else + u_put_unalignedp64(getPointer(), U_BYTESWAP64(i)); +# endif + + buffer_idx += sizeof(uint64_t); + + U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) + + U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) + } + + template void WriteScalar(T val, uint8_t byte_width) + { + U_TRACE(0, "UFlatBuffer::WriteScalar(%p,%u)", &val, byte_width) + + if (byte_width < 4) + { + if (byte_width < 2) WriteScalar8(val); + else WriteScalar16(val); + } + else if (byte_width < 8) WriteScalar32(val); + else WriteScalar64(val); + } + + void WriteFloat(float f) + { + U_TRACE(0, "UFlatBuffer::WriteFloat(%g)", f) + + char* p = (char*)&f; + + WriteScalar32(*(uint32_t*)p); + + U_INTERNAL_DUMP("writeFloat = %#.4S", getPointer()-4) + } + + void WriteDouble(double f, uint8_t byte_width) + { + U_TRACE(0, "UFlatBuffer::WriteDouble(%g,%u)", f, byte_width) + + if (byte_width == 4) WriteFloat(f); + else + { + U_INTERNAL_ASSERT_EQUALS(byte_width, 8) + + char* p = (char*)&f; + + WriteScalar64(*(uint64_t*)p); + + U_INTERNAL_DUMP("writeDouble = %#.8S", getPointer()-8) + } + } + + void WriteAny(uint8_t byte_width); + + void WriteOffset(uint32_t o, uint8_t byte_width) + { + U_TRACE(0, "UFlatBuffer::WriteOffset(%u,%u)", o, byte_width) + + uint32_t reloff = buffer_idx - o; + + U_INTERNAL_DUMP("buffer_idx = %u reloff(%u) = %#.4S", buffer_idx, reloff, buffer_str + o) + + U_INTERNAL_ASSERT(byte_width == 8 || reloff < (1ULL << (byte_width * 8))) + + WriteScalar(reloff, byte_width); + } + + static uint8_t Align(uint8_t alignment) { return (1U << alignment); } // Align to prepare for writing a scalar with a certain size + + // READ + + static uint8_t ReadScalar8(const void* p) + { + U_TRACE(0, "UFlatBuffer::ReadScalar8(%p)", p) + + return *(const uint8_t*)p; + } + + static uint16_t ReadScalar16(const void* p) + { + U_TRACE(0, "UFlatBuffer::ReadScalar16(%p)", p) + +# if __BYTE_ORDER == __LITTLE_ENDIAN + return u_get_unalignedp16(p); +# else + return U_BYTESWAP16(u_get_unalignedp16(p)); +# endif + } + + static uint32_t ReadScalar32(const void* p) + { + U_TRACE(0, "UFlatBuffer::ReadScalar32(%p)", p) + +# if __BYTE_ORDER == __LITTLE_ENDIAN + return u_get_unalignedp32(p); +# else + return U_BYTESWAP32(u_get_unalignedp32(p)); +# endif + } + + static uint64_t ReadScalar64(const void* p) + { + U_TRACE(0, "UFlatBuffer::ReadScalar64(%p)", p) + +# if __BYTE_ORDER == __LITTLE_ENDIAN + return u_get_unalignedp64(p); +# else + return U_BYTESWAP64(u_get_unalignedp64(p)); +# endif + } + + template static T ReadScalar(const void* p, uint8_t byte_width) + { + U_TRACE(0, "UFlatBuffer::ReadScalar(%#.*S,%u)", sizeof(T), p, byte_width) + + if (byte_width < 4) + { + if (byte_width < 2) return ReadScalar8(p); + + return ReadScalar16(p); + } + + if (byte_width < 8) return ReadScalar32(p); + + return ReadScalar64(p); + } + + static int64_t ReadInt64( const uint8_t* data, uint8_t byte_width) { return -ReadScalar(data, byte_width); } + static uint32_t ReadUInt32(const uint8_t* data, uint8_t byte_width) { return ReadScalar(data, byte_width); } + static uint64_t ReadUInt64(const uint8_t* data, uint8_t byte_width) { return ReadScalar(data, byte_width); } + + static float ReadFloat(const void* p) + { + U_TRACE(0, "UFlatBuffer::ReadFloat(%p)", p) + +# if __BYTE_ORDER == __LITTLE_ENDIAN + return *(float*)p; +# else + return U_BYTESWAP32(*(float*)p); +# endif + } + + static double ReadDouble(const void* p) + { + U_TRACE(0, "UFlatBuffer::ReadDouble(%p)", p) + +# if __BYTE_ORDER == __LITTLE_ENDIAN + return *(double*)p; +# else + return U_BYTESWAP64(*(double*)p); +# endif + } + + static double ReadDouble(const uint8_t* data, uint8_t byte_width) + { + U_TRACE(0, "UFlatBuffer::ReadDouble(%#.8S,%u)", data, byte_width) + + if (byte_width == 4) return ReadFloat(data); + + U_INTERNAL_ASSERT_EQUALS(byte_width, 8) + + return ReadDouble(data); + } + + static uint8_t* Indirect(const uint8_t* data, uint8_t parent_width) + { + U_TRACE(0, "UFlatBuffer::Indirect(%#.12S,%u)", data, parent_width) + + U_INTERNAL_DUMP("data-buffer_str = %u", data-buffer_str) + + uint32_t o = ReadUInt32(data, parent_width); + + U_INTERNAL_DUMP("o = %u", o) + + U_INTERNAL_DUMP("Indirect = %#.4S", (uint8_t*)data-o) + + return ((uint8_t*)data - o); + } + + uint8_t* Indirect() { return Indirect(data_, parent_width_); } + + template void PushIndirect(T val, uint8_t type, uint8_t bit_width) + { + U_TRACE(0, "UFlatBuffer::PushIndirect(%p,%u,%u)", &val, type, bit_width) + + uint32_t iloc = buffer_idx; + + uint8_t byte_width = Align(bit_width); + + WriteScalar(val, byte_width); + + pushOnStack(iloc, type, bit_width); + } + + void PushIndirectFloat(float f) + { + U_TRACE(0, "UFlatBuffer::PushIndirectFloat(%g)", f) + + uint32_t iloc = buffer_idx; + + WriteFloat(f); + + pushOnStack(iloc, UFlatBufferValue::TYPE_INDIRECT_FLOAT, UFlatBufferValue::BIT_WIDTH_32); + } + + uint32_t getSize(const uint8_t* data) const + { + U_TRACE(0, "UFlatBuffer::getSize(%#.4S)", data) + + U_INTERNAL_DUMP("byte_width_ = %u", byte_width_) + + uint32_t o = ReadUInt32(data - byte_width_, byte_width_); + + U_RETURN(o); + } + + void setIndirect(uint8_t* ptr, UFlatBuffer& fb, uint8_t type) const + { + U_TRACE(0, "UFlatBuffer::setIndirect(%p,%p,%u)", ptr, &fb, type) + + U_INTERNAL_DUMP("type_ = %u byte_width_ = %u parent_width_ = %u", type_, byte_width_, parent_width_) + + fb.byte_width_ = + fb.parent_width_ = byte_width_; + fb.type_ = type; + fb.buffer_idx = fb.getSize((fb.data_ = Indirect(ptr, parent_width_))); + + U_INTERNAL_DUMP("fb.data(%u) = %#.*S", fb.buffer_idx, fb.buffer_idx, fb.data_) + } + + void AsVector(uint8_t* ptr, UFlatBuffer& fb) const + { + U_TRACE(0, "UFlatBuffer::AsVector(%p,%p)", ptr, &fb) + + U_INTERNAL_ASSERT(IsVector()) + + setIndirect(ptr, fb, UFlatBufferValue::TYPE_VECTOR); + } + + void AsTypedVector(uint8_t* ptr, UFlatBuffer& fb) const + { + U_TRACE(0, "UFlatBuffer::AsTypedVector(%p,%p)", ptr, &fb) + + U_INTERNAL_ASSERT(IsTypedVector()) + + setIndirect(ptr, fb, ToTypedVectorElementType()); + } + + void AsFixedTypedVector(uint8_t* ptr, UFlatBuffer& fb) const + { + U_TRACE(0, "UFlatBuffer::AsFixedTypedVector(%p,%p)", ptr, &fb) + + U_INTERNAL_ASSERT(IsFixedTypedVector()) + + fb.data_ = Indirect(ptr, parent_width_); + fb.byte_width_ = + fb.parent_width_ = byte_width_; + fb.type_ = ToFixedTypedVectorElementType(fb); + + U_INTERNAL_DUMP("fb.data(%u) = %#.*S", fb.buffer_idx, fb.buffer_idx, fb.data_) + } + + void AsMap(uint8_t* ptr, UFlatBuffer& fb) const + { + U_TRACE(0, "UFlatBuffer::AsMap(%p,%p)", ptr, &fb) + + U_INTERNAL_ASSERT(IsMap()) + + setIndirect(ptr, fb, UFlatBufferValue::TYPE_MAP); + } + + void AsMapGetKeys(uint8_t* ptr, UFlatBuffer& fb) const + { + U_TRACE(0, "UFlatBuffer::AsMapGetKeys(%p,%p)", ptr, &fb) + + U_DUMP("type_ = (%u,%S) byte_width_ = %u parent_width_ = %u", type_, getTypeDescription(type_), byte_width_, parent_width_) + + U_INTERNAL_ASSERT(IsMap()) + + uint8_t* keys_offset = ptr - (byte_width_ * 3); + + fb.byte_width_ = + fb.parent_width_ = ReadUInt32(keys_offset + byte_width_, byte_width_); + fb.type_ = UFlatBufferValue::TYPE_STRING; + fb.buffer_idx = fb.getSize((fb.data_ = Indirect(keys_offset, byte_width_))); + + U_INTERNAL_DUMP("fb.data(%u) = %#.*S", fb.buffer_idx, fb.buffer_idx, fb.data_) + } + + void AsMapGetValues(uint8_t* ptr, UFlatBuffer& fb) const + { + U_TRACE(0, "UFlatBuffer::AsMapGetValues(%p,%p)", ptr, &fb) + + U_DUMP("type_ = (%u,%S) byte_width_ = %u parent_width_ = %u", type_, getTypeDescription(type_), byte_width_, parent_width_) + + U_INTERNAL_ASSERT(IsMap()) + + fb.byte_width_ = + fb.parent_width_ = byte_width_; + fb.type_ = UFlatBufferValue::TYPE_VECTOR; + fb.buffer_idx = fb.getSize((fb.data_ = ptr)); + + U_INTERNAL_DUMP("fb.data(%u) = %#.*S", fb.buffer_idx, fb.buffer_idx, fb.data_) + } + + void setTypeAndWidth(uint8_t packed_type) + { + U_TRACE(0, "UFlatBuffer::setTypeAndWidth(%u)", packed_type) + + byte_width_ = 1U << (packed_type & 3); + + type_ = packed_type >> 2; + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S) packed_type = %u", parent_width_, byte_width_, type_, getTypeDescription(type_), packed_type) + } + + uint8_t* AsVectorSetIndex(uint32_t i) + { + U_TRACE(0, "UFlatBuffer::AsVectorSetIndex(%u)", i) + + U_DUMP("type_ = (%u,%S)", type_, getTypeDescription(type_)) + + U_ASSERT_MINOR(i, buffer_idx) + U_INTERNAL_ASSERT(IsVector() || IsMap()) + + uint8_t* ptr = data_; + uint32_t offset = i * (parent_width_ = byte_width_); + + setTypeAndWidth(ptr[(buffer_idx * byte_width_) + i]); + + return (ptr + offset); + } + + uint8_t* AsTypedOrFixedVectorSetIndex(uint32_t i) + { + U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorSetIndex(%u)", i) + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) + + U_ASSERT_MINOR(i, buffer_idx) + U_INTERNAL_ASSERT(IsTypedVector() || IsTypedVectorElementType()) + + uint8_t* ptr = (data_ + i * (parent_width_ = byte_width_)); + + byte_width_ = 1; + + return ptr; + } + + uint8_t* AsMapSetIndex(const char* key, uint32_t len); + + void AsVectorGet(uint32_t i, UFlatBuffer& fb) const + { + U_TRACE(0, "UFlatBuffer::AsVectorGet(%u,%p)", i, &fb) + + U_ASSERT_MINOR(i, buffer_idx) + U_INTERNAL_ASSERT(IsVector()) + + fb.data_ = data_ + (i * byte_width_); + fb.parent_width_ = parent_width_; + + fb.setTypeAndWidth(data_[(buffer_idx * byte_width_) + i]); + + fb.buffer_idx = fb.byte_width_; + + U_INTERNAL_DUMP("fb.data(%u) = %#.*S", fb.buffer_idx, fb.buffer_idx, fb.data_) + } + + void AsTypedOrFixedVectorGet(uint32_t i, UFlatBuffer& fb) const + { + U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGet(%u,%p)", i, &fb) + + U_ASSERT_MINOR(i, buffer_idx) + U_INTERNAL_ASSERT(IsTypedVector() || IsTypedVectorElementType()) + + fb.buffer_idx = + fb.byte_width_ = 1; + + fb.data_ = data_ + (i * byte_width_); + fb.parent_width_ = parent_width_; + + U_INTERNAL_DUMP("fb.data(%u) = %#.*S", fb.buffer_idx, fb.buffer_idx, fb.data_) + } + + bool AsBool(const uint8_t* ptr) const + { + U_TRACE(0, "UFlatBuffer::AsBool(%p)", ptr) + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) + + U_INTERNAL_ASSERT(IsBool()) + + if (ReadUInt64(ptr, parent_width_)) U_RETURN(true); + + U_RETURN(false); + } + + uint64_t AsUInt64(const uint8_t* ptr) const + { + U_TRACE(0, "UFlatBuffer::AsUInt64(%p)", ptr) + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) + + U_INTERNAL_ASSERT(IsIntOrUint()) + + return ReadUInt64(ptr, parent_width_); + } + + uint64_t AsIndirectUInt64(const uint8_t* ptr) const + { + U_TRACE(0, "UFlatBuffer::AsIndirectUInt64(%p)", ptr) + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) + + U_INTERNAL_ASSERT(IsIntOrUint()) + + return ReadUInt64(Indirect(ptr, parent_width_), byte_width_); + } + + int64_t AsInt64(const uint8_t* ptr) const + { + U_TRACE(0, "UFlatBuffer::AsInt64(%p)", ptr) + + U_INTERNAL_ASSERT(IsInt()) + + return ReadInt64(ptr, parent_width_); + } + + int64_t AsIndirectInt64(const uint8_t* ptr) const + { + U_TRACE(0, "UFlatBuffer::AsIndirectInt64(%p)", ptr) + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) + + U_INTERNAL_ASSERT(IsInt()) + + return ReadInt64(Indirect(ptr, parent_width_), byte_width_); + } + + float AsFloat(const uint8_t* ptr) const + { + U_TRACE(0, "UFlatBuffer::AsFloat(%p)", ptr) + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) + + U_INTERNAL_ASSERT(IsFloat()) + + U_INTERNAL_ASSERT_EQUALS(parent_width_, 4) + + return *(float*)ptr; + } + + double AsIndirectFloat(const uint8_t* ptr) const + { + U_TRACE(0, "UFlatBuffer::AsIndirectFloat(%p)", ptr) + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) + + U_INTERNAL_ASSERT(IsFloat()) + + U_INTERNAL_ASSERT_EQUALS(byte_width_, 4) + + return *(float*)Indirect(ptr, parent_width_); + } + + double AsDouble(const uint8_t* ptr) const + { + U_TRACE(0, "UFlatBuffer::AsDouble(%p)", ptr) + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) + + U_INTERNAL_ASSERT(IsFloat()) + + return ReadDouble(ptr, parent_width_); + } + + double AsIndirectDouble(const uint8_t* ptr) const + { + U_TRACE(0, "UFlatBuffer::AsIndirectDouble(%p)", ptr) + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) + + U_INTERNAL_ASSERT(IsFloat()) + + return ReadDouble(Indirect(ptr, parent_width_), byte_width_); + } + + bool GetBool(const uint8_t* ptr) + { + U_TRACE(0, "UFlatBuffer::GetBool(%p)", ptr) + + bool value = AsBool(ptr); + + byte_width_ = parent_width_; + + U_RETURN(value); + } + + uint64_t GetUInt64(const uint8_t* ptr) + { + U_TRACE(0, "UFlatBuffer::GetUInt64(%p)", ptr) + + uint64_t value = AsUInt64(ptr); + + byte_width_ = parent_width_; + + U_RETURN(value); + } + + uint64_t GetIndirectUInt64(const uint8_t* ptr) + { + U_TRACE(0, "UFlatBuffer::GetIndirectUInt64(%p)", ptr) + + uint64_t value = AsIndirectUInt64(ptr); + + byte_width_ = parent_width_; + + U_RETURN(value); + } + + float GetFloat(const uint8_t* ptr) + { + U_TRACE(0, "UFlatBuffer::GetFloat(%p)", ptr) + + float value = AsFloat(ptr); + + byte_width_ = parent_width_; + + U_RETURN(value); + } + + float GetIndirectFloat(const uint8_t* ptr) + { + U_TRACE(0, "UFlatBuffer::GetIndirectFloat(%p)", ptr) + + float value = AsIndirectFloat(ptr); + + byte_width_ = parent_width_; + + U_RETURN(value); + } + + double GetDouble(const uint8_t* ptr) + { + U_TRACE(0, "UFlatBuffer::GetDouble(%p)", ptr) + + double value = AsDouble(ptr); + + byte_width_ = parent_width_; + + U_RETURN(value); + } + + double GetIndirectDouble(const uint8_t* ptr) + { + U_TRACE(0, "UFlatBuffer::GetIndirectDouble(%p)", ptr) + + double value = AsIndirectDouble(ptr); + + byte_width_ = parent_width_; + + U_RETURN(value); + } + + UString AsString(const uint8_t* ptr) const + { + U_TRACE(0, "UFlatBuffer::AsString(%p)", ptr) + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) + + U_INTERNAL_ASSERT(IsString()) + + uint8_t* str = Indirect(ptr, parent_width_); + + UString x((const char*)str, getSize(str)); + + U_RETURN_STRING(x); + } + + UString GetString(const uint8_t* ptr) + { + U_TRACE(0, "UFlatBuffer::GetString(%p)", ptr) + + UString x = AsString(ptr); + + byte_width_ = parent_width_; + + U_RETURN_STRING(x); + } + + template T As(const uint8_t* ptr) + { + U_TRACE(0, "UFlatBuffer::As(%p)", ptr) + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) + + return ReadUInt64(ptr, parent_width_); + } + + template T AsIndirect(const uint8_t* ptr) + { + U_TRACE(0, "UFlatBuffer::AsIndirect(%p)", ptr) + + U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) + + return ReadUInt64(Indirect(ptr, parent_width_), byte_width_); + } + + template T Get(const uint8_t* ptr) + { + U_TRACE(0, "UFlatBuffer::Get(%p)", ptr) + + T value = As(ptr); + + byte_width_ = parent_width_; + + return value; + } + + template T GetIndirect(const uint8_t* ptr) + { + U_TRACE(0, "UFlatBuffer::GetIndirect(%p)", ptr) + + T value = AsIndirect(ptr); + + byte_width_ = parent_width_; + + return value; + } + +private: + U_DISALLOW_COPY_AND_ASSIGN(UFlatBuffer) + + friend class UValue; + + template friend class UFlatBufferTypeHandler; +}; + +// Template specialization + +template<> inline bool UFlatBuffer::As( const uint8_t* ptr) { return AsBool(ptr); } +template<> inline uint64_t UFlatBuffer::As(const uint8_t* ptr) { return AsUInt64(ptr); } +template<> inline float UFlatBuffer::As( const uint8_t* ptr) { return AsFloat(ptr); } +template<> inline double UFlatBuffer::As( const uint8_t* ptr) { return AsDouble(ptr); } +template<> inline UString UFlatBuffer::As( const uint8_t* ptr) { return AsString(ptr); } + +template<> inline uint64_t UFlatBuffer::AsIndirect(const uint8_t* ptr) { return AsIndirectUInt64(ptr); } +template<> inline float UFlatBuffer::AsIndirect( const uint8_t* ptr) { return AsIndirectFloat(ptr); } +template<> inline double UFlatBuffer::AsIndirect( const uint8_t* ptr) { return AsIndirectDouble(ptr); } + +template<> inline bool UFlatBuffer::Get( const uint8_t* ptr) { return GetBool(ptr); } +template<> inline uint64_t UFlatBuffer::Get(const uint8_t* ptr) { return GetUInt64(ptr); } +template<> inline float UFlatBuffer::Get( const uint8_t* ptr) { return GetFloat(ptr); } +template<> inline double UFlatBuffer::Get( const uint8_t* ptr) { return GetDouble(ptr); } +template<> inline UString UFlatBuffer::Get( const uint8_t* ptr) { return GetString(ptr); } + +template<> inline uint64_t UFlatBuffer::GetIndirect(const uint8_t* ptr) { return GetIndirectUInt64(ptr); } +template<> inline float UFlatBuffer::GetIndirect( const uint8_t* ptr) { return GetIndirectFloat(ptr); } +template<> inline double UFlatBuffer::GetIndirect( const uint8_t* ptr) { return GetIndirectDouble(ptr); } + +// VECTOR + +template<> inline bool UFlatBuffer::AsVectorGet(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsVectorGet(%u)", i) + + bool value = Get(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_VECTOR; + + U_RETURN(value); +} + +template<> inline bool UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGet(%u)", i) + + return Get(AsTypedOrFixedVectorSetIndex(i)); +} + +template<> inline uint64_t UFlatBuffer::AsVectorGet(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsVectorGet(%u)", i) + + uint64_t value = Get(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_VECTOR; + + U_RETURN(value); +} + +template<> inline uint64_t UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGet(%u)", i) + + return Get(AsTypedOrFixedVectorSetIndex(i)); +} + +template<> inline int8_t UFlatBuffer::AsVectorGet( uint32_t i) { return -(int8_t) AsVectorGet(i); } +template<> inline int16_t UFlatBuffer::AsVectorGet(uint32_t i) { return -(int16_t)AsVectorGet(i); } +template<> inline int32_t UFlatBuffer::AsVectorGet(uint32_t i) { return -(int32_t)AsVectorGet(i); } +template<> inline int64_t UFlatBuffer::AsVectorGet(uint32_t i) { return -(int64_t)AsVectorGet(i); } + +template<> inline uint64_t UFlatBuffer::AsVectorGetIndirect(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsVectorGetIndirect(%u)", i) + + uint64_t value = GetIndirect(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_VECTOR; + + U_RETURN(value); +} + +template<> inline uint64_t UFlatBuffer::AsTypedOrFixedVectorGetIndirect(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGetIndirect(%u)", i) + + return GetIndirectUInt64(AsTypedOrFixedVectorSetIndex(i)); +} + +template<> inline int8_t UFlatBuffer::AsVectorGetIndirect( uint32_t i) { return -(int8_t) AsVectorGetIndirect(i); } +template<> inline int16_t UFlatBuffer::AsVectorGetIndirect(uint32_t i) { return -(int16_t)AsVectorGetIndirect(i); } +template<> inline int32_t UFlatBuffer::AsVectorGetIndirect(uint32_t i) { return -(int32_t)AsVectorGetIndirect(i); } +template<> inline int64_t UFlatBuffer::AsVectorGetIndirect(uint32_t i) { return -(int64_t)AsVectorGetIndirect(i); } + +template<> inline int8_t UFlatBuffer::AsTypedOrFixedVectorGet( uint32_t i) { return -(int8_t) AsTypedOrFixedVectorGet(i); } +template<> inline int16_t UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) { return -(int16_t)AsTypedOrFixedVectorGet(i); } +template<> inline int32_t UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) { return -(int32_t)AsTypedOrFixedVectorGet(i); } +template<> inline int64_t UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) { return -(int64_t)AsTypedOrFixedVectorGet(i); } + +template<> inline int8_t UFlatBuffer::AsTypedOrFixedVectorGetIndirect( uint32_t i) { return -(int8_t) AsTypedOrFixedVectorGetIndirect(i); } +template<> inline int16_t UFlatBuffer::AsTypedOrFixedVectorGetIndirect(uint32_t i) { return -(int16_t)AsTypedOrFixedVectorGetIndirect(i); } +template<> inline int32_t UFlatBuffer::AsTypedOrFixedVectorGetIndirect(uint32_t i) { return -(int32_t)AsTypedOrFixedVectorGetIndirect(i); } +template<> inline int64_t UFlatBuffer::AsTypedOrFixedVectorGetIndirect(uint32_t i) { return -(int64_t)AsTypedOrFixedVectorGetIndirect(i); } + +template<> inline double UFlatBuffer::AsVectorGet(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsVectorGet(%u)", i) + + double value = Get(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_VECTOR; + + U_RETURN(value); +} + +template<> inline double UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGet(%u)", i) + + return Get(AsTypedOrFixedVectorSetIndex(i)); +} + +template<> inline double UFlatBuffer::AsVectorGetIndirect(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsVectorGetIndirect(%u)", i) + + double value = GetIndirect(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_VECTOR; + + U_RETURN(value); +} + +template<> inline double UFlatBuffer::AsTypedOrFixedVectorGetIndirect(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGetIndirect(%u)", i) + + return GetIndirect(AsTypedOrFixedVectorSetIndex(i)); +} + +template<> inline UString UFlatBuffer::AsVectorGet(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsVectorGet(%u)", i) + + UString value = Get(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_VECTOR; + + U_RETURN_STRING(value); +} + +template<> inline UString UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGet(%u)", i) + + return Get(AsTypedOrFixedVectorSetIndex(i)); +} + +// MAP + +template<> inline bool UFlatBuffer::AsMapGet(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsMapGet(%u)", i) + + U_INTERNAL_ASSERT(IsMap()) + + bool value = Get(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_MAP; + + U_RETURN(value); +} + +template<> inline bool UFlatBuffer::AsMapGet(const char* key, uint32_t len) +{ + U_TRACE(0, "UFlatBuffer::AsMapGet(%.*S,%u)", len, key, len) + + U_INTERNAL_ASSERT(IsMap()) + + bool value = Get(AsMapSetIndex(key, len)); + + type_ = UFlatBufferValue::TYPE_MAP; + + U_RETURN(value); +} + +template<> inline uint64_t UFlatBuffer::AsMapGet(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsMapGet(%u)", i) + + U_INTERNAL_ASSERT(IsMap()) + + uint64_t value = Get(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_MAP; + + U_RETURN(value); +} + +template<> inline uint64_t UFlatBuffer::AsMapGet(const char* key, uint32_t len) +{ + U_TRACE(0, "UFlatBuffer::AsMapGet(%.*S,%u)", len, key, len) + + U_INTERNAL_ASSERT(IsMap()) + + uint64_t value = Get(AsMapSetIndex(key, len)); + + type_ = UFlatBufferValue::TYPE_MAP; + + U_RETURN(value); +} + +template<> inline int8_t UFlatBuffer::AsMapGet( uint32_t i) { return -(int8_t) AsMapGet(i); } +template<> inline int16_t UFlatBuffer::AsMapGet(uint32_t i) { return -(int16_t)AsMapGet(i); } +template<> inline int32_t UFlatBuffer::AsMapGet(uint32_t i) { return -(int32_t)AsMapGet(i); } +template<> inline int64_t UFlatBuffer::AsMapGet(uint32_t i) { return -(int64_t)AsMapGet(i); } + +template<> inline int8_t UFlatBuffer::AsMapGet( const char* key, uint32_t len) { return -(int8_t) AsMapGet(key, len); } +template<> inline int16_t UFlatBuffer::AsMapGet(const char* key, uint32_t len) { return -(int16_t)AsMapGet(key, len); } +template<> inline int32_t UFlatBuffer::AsMapGet(const char* key, uint32_t len) { return -(int32_t)AsMapGet(key, len); } +template<> inline int64_t UFlatBuffer::AsMapGet(const char* key, uint32_t len) { return -(int64_t)AsMapGet(key, len); } + +template<> inline uint64_t UFlatBuffer::AsMapGetIndirect(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsMapGetIndirect(%u)", i) + + U_INTERNAL_ASSERT(IsMap()) + + uint64_t value = GetIndirect(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_MAP; + + U_RETURN(value); +} + +template<> inline uint64_t UFlatBuffer::AsMapGetIndirect(const char* key, uint32_t len) +{ + U_TRACE(0, "UFlatBuffer::AsMapGetIndirect(%.*S,%u)", len, key, len) + + U_INTERNAL_ASSERT(IsMap()) + + uint64_t value = GetIndirect(AsMapSetIndex(key, len)); + + type_ = UFlatBufferValue::TYPE_MAP; + + U_RETURN(value); +} + +template<> inline int8_t UFlatBuffer::AsMapGetIndirect( uint32_t i) { return -(int8_t) AsMapGetIndirect(i); } +template<> inline int16_t UFlatBuffer::AsMapGetIndirect(uint32_t i) { return -(int16_t)AsMapGetIndirect(i); } +template<> inline int32_t UFlatBuffer::AsMapGetIndirect(uint32_t i) { return -(int32_t)AsMapGetIndirect(i); } +template<> inline int64_t UFlatBuffer::AsMapGetIndirect(uint32_t i) { return -(int64_t)AsMapGetIndirect(i); } + +template<> inline int8_t UFlatBuffer::AsMapGetIndirect( const char* key, uint32_t len) { return -(int8_t) AsMapGetIndirect(key, len); } +template<> inline int16_t UFlatBuffer::AsMapGetIndirect(const char* key, uint32_t len) { return -(int16_t)AsMapGetIndirect(key, len); } +template<> inline int32_t UFlatBuffer::AsMapGetIndirect(const char* key, uint32_t len) { return -(int32_t)AsMapGetIndirect(key, len); } +template<> inline int64_t UFlatBuffer::AsMapGetIndirect(const char* key, uint32_t len) { return -(int64_t)AsMapGetIndirect(key, len); } + +template<> inline double UFlatBuffer::AsMapGet(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsMapGet(%u)", i) + + U_INTERNAL_ASSERT(IsMap()) + + double value = Get(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_MAP; + + U_RETURN(value); +} + +template<> inline double UFlatBuffer::AsMapGet(const char* key, uint32_t len) +{ + U_TRACE(0, "UFlatBuffer::AsMapGet(%.*S,%u)", len, key, len) + + U_INTERNAL_ASSERT(IsMap()) + + double value = Get(AsMapSetIndex(key, len)); + + type_ = UFlatBufferValue::TYPE_MAP; + + U_RETURN(value); +} + +template<> inline double UFlatBuffer::AsMapGetIndirect(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsMapGetIndirect(%u)", i) + + U_INTERNAL_ASSERT(IsMap()) + + double value = GetIndirect(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_MAP; + + U_RETURN(value); +} + +template<> inline double UFlatBuffer::AsMapGetIndirect(const char* key, uint32_t len) +{ + U_TRACE(0, "UFlatBuffer::AsMapGetIndirect(%.*S,%u)", len, key, len) + + U_INTERNAL_ASSERT(IsMap()) + + double value = GetIndirect(AsMapSetIndex(key, len)); + + type_ = UFlatBufferValue::TYPE_MAP; + + U_RETURN(value); +} + +template<> inline UString UFlatBuffer::AsMapGet(uint32_t i) +{ + U_TRACE(0, "UFlatBuffer::AsMapGet(%u)", i) + + U_INTERNAL_ASSERT(IsMap()) + + UString value = Get(AsVectorSetIndex(i)); + + type_ = UFlatBufferValue::TYPE_MAP; + + U_RETURN_STRING(value); +} + +template<> inline UString UFlatBuffer::AsMapGet(const char* key, uint32_t len) +{ + U_TRACE(0, "UFlatBuffer::AsMapGet(%.*S,%u)", len, key, len) + + U_INTERNAL_ASSERT(IsMap()) + + UString value = Get(AsMapSetIndex(key, len)); + + type_ = UFlatBufferValue::TYPE_MAP; + + U_RETURN_STRING(value); +} + +// manage object <=> FlatBuffer representation + +class U_EXPORT UFlatBufferTypeHandler_Base { +public: + // Check for memory error + U_MEMORY_TEST + + // Allocator e Deallocator + U_MEMORY_ALLOCATOR + U_MEMORY_DEALLOCATOR + + UFlatBufferTypeHandler_Base(const void* ptr) : pval((void*)ptr) + { + U_TRACE_REGISTER_OBJECT(0, UFlatBufferTypeHandler_Base, "%p", ptr) + + U_INTERNAL_ASSERT_POINTER(pval) + } + + ~UFlatBufferTypeHandler_Base() + { + U_TRACE_UNREGISTER_OBJECT(0, UFlatBufferTypeHandler_Base) + + U_INTERNAL_ASSERT_POINTER(pval) + } + +#ifdef DEBUG + const char* dump(bool _reset) const; +#endif + +protected: + void* pval; + +private: + U_DISALLOW_ASSIGN(UFlatBufferTypeHandler_Base) +}; + +#define FLATBUFFER(name_object_member, type_object_member) UFlatBufferTypeHandler(name_object_member) + +/** + * Provide template specializations to support your own complex types + * + * Take as example the following (simplified) class: + * + * class Person { + * public: + * int age; + * UString lastName; + * UString firstName; + * }; + * + * add this methods to the (simplified) class: + * + * void Person::toFlatBuffer(UFlatBuffer& fb) + * { + * fb.toFlatBuffer(FLATBUFFER(age, int)); + * fb.toFlatBuffer(FLATBUFFER( lastName, UString)); + * fb.toFlatBuffer(FLATBUFFER(firstName, UString)); + * } + * + * void Person::fromFlatBuffer(UFlatBuffer& fb) + * { + * fb.fromFlatBuffer(0, FLATBUFFER(age, int)); + * fb.fromFlatBuffer(1, FLATBUFFER( lastName, UString)); + * fb.fromFlatBuffer(2, FLATBUFFER(firstName, UString)); + * } + */ + +template class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(T* val) : UFlatBufferTypeHandler_Base( val) {} + explicit UFlatBufferTypeHandler(T& val) : UFlatBufferTypeHandler_Base(&val) {} + + // SERVICES + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + uint32_t start = fb.StartVector(); + + ((T*)pval)->toFlatBuffer(fb); + + fb.EndVector(start, false); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + UFlatBuffer vec; + + fb.AsVector(vec); + + ((T*)pval)->fromFlatBuffer(vec); + } + +private: + U_DISALLOW_ASSIGN(UFlatBufferTypeHandler) +}; + +template void UFlatBuffer::fromObject(T& obj) +{ + U_TRACE(0, "UFlatBuffer::fromObject(%p)", &obj) + + StartBuild(); + + UFlatBufferTypeHandler(obj).toFlatBuffer(*this); + + setRoot(buffer_str, EndBuild()); +} + +template void UFlatBuffer::toObject(T& obj) +{ + U_TRACE(0, "UFlatBuffer::toObject(%p)", &obj) + + UFlatBufferTypeHandler(obj).fromFlatBuffer(*this); +} + +// TEMPLATE SPECIALIZATIONS + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(null&) : UFlatBufferTypeHandler_Base(U_NULLPTR) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.Null(); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + U_VAR_UNUSED(fb) + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(bool& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.Bool(*(bool*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(bool*)pval = fb.AsBool(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(char& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.UInt(*(char*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(char*)pval = fb.AsUInt64(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(unsigned char& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.UInt(*(unsigned char*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(unsigned char*)pval = fb.AsUInt64(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(short& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.UInt(*(short*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(short*)pval = fb.AsUInt64(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(unsigned short& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.UInt(*(unsigned short*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(unsigned short*)pval = fb.AsUInt64(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(int& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.setNumber(*(int*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(int*)pval = fb.AsNumber(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(unsigned int& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.UInt(*(unsigned int*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(unsigned int*)pval = fb.AsUInt64(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(long& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.setNumber(*(long*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(long*)pval = fb.AsNumber(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(unsigned long& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.UInt(*(unsigned long*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(unsigned long*)pval = fb.AsUInt64(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(long long& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.setNumber(*(int64_t*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(long long*)pval = fb.AsNumber(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(unsigned long long& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.UInt(*(uint64_t*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(unsigned long long*)pval = fb.AsNumber(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(float& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.Double(*(float*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(float*)pval = fb.AsDouble(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(double& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.Double(*(double*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(double*)pval = fb.AsDouble(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(long double& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.Double(*(long double*)pval); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + *(long double*)pval = fb.AsDouble(); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(UStringRep& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.String(U_STRING_TO_PARAM(*(UStringRep*)pval)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + U_ASSERT(fb.IsString()) + + U_ERROR("UFlatBufferTypeHandler::fromFlatBuffer(): sorry, we cannot use UStringRep type from FLATBUFFER handler..."); + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { +public: + explicit UFlatBufferTypeHandler(UString& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + fb.String(U_STRING_TO_PARAM(*(UString*)pval)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + U_ASSERT(fb.IsString()) + + *(UString*)pval = fb.AsString(); + } +}; + +// TEMPLATE SPECIALIZATIONS FOR CONTAINERS + +template class U_EXPORT UFlatBufferTypeHandler > : public UFlatBufferTypeHandler_Base { +public: + typedef UVector uvector; + + explicit UFlatBufferTypeHandler(uvector& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + uvector* pvec = (uvector*)pval; + + if (pvec->_length == 0) fb.AddVectorEmpty(); + else + { + const void** ptr = pvec->vec; + const void** end = pvec->vec + pvec->_length; + + uint32_t start = fb.StartVector(); + + do { UFlatBufferTypeHandler(*(T*)(*ptr)).toFlatBuffer(fb); } while (++ptr < end); + + fb.EndVector(start, false); + } + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + U_ASSERT(((uvector*)pval)->empty()) + + bool typed, fixed; + UFlatBuffer vec, fbb; + + fixed = ((typed = fb.IsTypedVector()) ? false : fb.IsFixedTypedVector()); + + if (typed) fb.AsTypedVector(vec); + else if (fixed) fb.AsFixedTypedVector(vec), typed = true; + else fb.AsVector(vec); + + for (uint32_t i = 0, n = vec.GetSize(); i < n; ++i) + { + T* pitem; + + U_NEW(T, pitem, T); + + if (typed == false) vec.AsVectorGet(i, fbb); + else vec.AsTypedOrFixedVectorGet(i, fbb); + + UFlatBufferTypeHandler(*pitem).fromFlatBuffer(fbb); + + ((UVector*)pval)->push_back(pitem); + } + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler > : public UFlatBufferTypeHandler > { +public: + typedef UVector uvectorbase; + + explicit UFlatBufferTypeHandler(UVector& val) : UFlatBufferTypeHandler(*((uvector*)&val)) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler>::toFlatBuffer(%p)", &fb) + + uvectorbase* pvec = (uvectorbase*)pval; + + if (pvec->_length == 0) fb.AddVectorEmpty(); + else + { + const void** ptr = pvec->vec; + const void** end = pvec->vec + pvec->_length; + + uint32_t start = fb.StartVector(); + + do { fb.String(U_STRING_TO_PARAM(*(const UStringRep*)(*ptr))); } while (++ptr < end); + + fb.EndVector(start); + } + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler>::fromFlatBuffer(%p)", &fb) + + U_ASSERT(((UVector*)pval)->empty()) + + UFlatBuffer vec; + + fb.AsTypedVector(vec); + + for (uint32_t i = 0, n = vec.GetSize(); i < n; ++i) + { + ((UVector*)pval)->push_back(vec.AsTypedOrFixedVectorGet(i)); + } + } +}; + +template class U_EXPORT UFlatBufferTypeHandler > : public UFlatBufferTypeHandler_Base { +public: + typedef UHashMap uhashmap; + + explicit UFlatBufferTypeHandler(uhashmap& map) : UFlatBufferTypeHandler_Base(&map) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + uhashmap* pmap = (uhashmap*)pval; + + if (pmap->first() == false) fb.AddMapEmpty(); + else + { + uint32_t start = fb.StartMap(); + + do { + fb.Key(U_STRING_TO_PARAM(pmap->getKey())); + + UFlatBufferTypeHandler(*(pmap->elem())).toFlatBuffer(fb); + } + while (pmap->next()); + + fb.EndMap(start); + } + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + U_ASSERT(((uhashmap*)pval)->empty()) + + UFlatBuffer map, keys, values, fbb; + + fb.AsMap(map); + + map.AsMapGetKeys(keys); + map.AsMapGetValues(values); + + for (uint32_t i = 0, n = map.GetSize(); i < n; ++i) + { + T* pitem; + + U_NEW(T, pitem, T); + + values.AsVectorGet(i, fbb); + + UFlatBufferTypeHandler(*pitem).fromFlatBuffer(fbb); + +# ifndef HAVE_OLD_IOSTREAM + ((uhashmap*)pval)->insert(keys.AsTypedOrFixedVectorGet(i), pitem); +# endif + } + } +}; + +template <> class U_EXPORT UFlatBufferTypeHandler > : public UFlatBufferTypeHandler > { +public: + typedef UHashMap uhashmapbase; + + explicit UFlatBufferTypeHandler(UHashMap& val) : UFlatBufferTypeHandler(*((uhashmap*)&val)) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler>::toFlatBuffer(%p)", &fb) + + UHashMap* pmap = (UHashMap*)pval; + + if (pmap->first() == false) fb.AddMapEmpty(); + else + { + uint32_t start = fb.StartMap(); + + do { + fb.Key(U_STRING_TO_PARAM(pmap->getKey())); + + fb.String(U_STRING_TO_PARAM(*(const UStringRep*)pmap->elem())); + } + while (pmap->next()); + + fb.EndMap(start); + } + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler>::fromFlatBuffer(%p)", &fb) + + U_ASSERT(((UHashMap*)pval)->empty()) + + UFlatBuffer map, keys, values, fbb; + + fb.AsMap(map); + + map.AsMapGetKeys(keys); + map.AsMapGetValues(values); + + for (uint32_t i = 0, n = map.GetSize(); i < n; ++i) + { + ((UHashMap*)pval)->insert(keys.AsTypedOrFixedVectorGet(i), values.AsVectorGet(i)); + } + } +}; + +#ifdef U_STDCPP_ENABLE +# include + +template class U_EXPORT UFlatBufferTypeHandler > : public UFlatBufferTypeHandler_Base { +public: + typedef std::vector stdvector; + + explicit UFlatBufferTypeHandler(stdvector& val) : UFlatBufferTypeHandler_Base(&val) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + stdvector* pvec = (stdvector*)pval; + + uint32_t n = pvec->size(); + + if (n == 0) fb.AddVectorEmpty(); + else + { + uint32_t start = fb.StartVector(); + + for (uint32_t i = 0; i < n; ++i) UFlatBufferTypeHandler(pvec->at(i)).toFlatBuffer(fb); + + fb.EndVector(start); + } + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + U_ASSERT(((stdvector*)pval)->empty()) + + bool typed, fixed; + UFlatBuffer vec, fbb; + + fixed = ((typed = fb.IsTypedVector()) ? false : fb.IsFixedTypedVector()); + + if (typed) fb.AsTypedVector(vec); + else if (fixed) fb.AsFixedTypedVector(vec), typed = true; + else fb.AsVector(vec); + + for (uint32_t i = 0, n = vec.GetSize(); i < n; ++i) + { + T item; + + if (typed == false) vec.AsVectorGet(i, fbb); + else vec.AsTypedOrFixedVectorGet(i, fbb); + + UFlatBufferTypeHandler(item).fromFlatBuffer(fbb); + + ((stdvector*)pval)->push_back(item); + } + } +}; + +# if defined(HAVE_CXX17) && !defined(__clang__) +# include + +template class U_EXPORT UFlatBufferTypeHandler > : public UFlatBufferTypeHandler_Base { +public: + typedef std::unordered_map stringtobitmaskmap; + + explicit UFlatBufferTypeHandler(stringtobitmaskmap& map) : UFlatBufferTypeHandler_Base(&map) {} + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) + + stringtobitmaskmap* pmap = (stringtobitmaskmap*)pval; + + if (pmap->empty()) fb.AddMapEmpty(); + else + { + uint32_t start = fb.StartMap(); + + // this is is C++17 vvv + for (const auto & [ key, value ] : *pmap) fb.toFlatBuffer(key, UFlatBufferTypeHandler(value)); + + fb.EndMap(start); + } + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) + + U_ASSERT(((stringtobitmaskmap*)pval)->empty()) + + UFlatBuffer map, keys, values, fbb; + + fb.AsMap(map); + + map.AsMapGetKeys(keys); + map.AsMapGetValues(values); + + for (uint32_t i = 0, n = map.GetSize(); i < n; ++i) + { + T* pitem; + + U_NEW(T, pitem, T); + + values.AsVectorGet(i, fbb); + + UFlatBufferTypeHandler(*pitem).fromFlatBuffer(fbb); + + ((stringtobitmaskmap*)pval)->insert_or_assign(keys.AsTypedOrFixedVectorGet(i), pitem); // insert_or_assign is C++17 + } + } +}; +# endif +#endif +#endif diff --git a/include/ulib/string.h b/include/ulib/string.h index 488eb83a..68c94ab1 100644 --- a/include/ulib/string.h +++ b/include/ulib/string.h @@ -114,6 +114,7 @@ class UPop3Client; class UHttpPlugIn; class UProxyPlugIn; class Application; +class UFlatBuffer; class UServer_Base; class UHashMapNode; class UHashTableNode; @@ -1016,6 +1017,7 @@ private: friend class UMimeHeader; friend class UHttpPlugIn; friend class Application; + friend class UFlatBuffer; friend class UProxyPlugIn; friend class UHashMapNode; friend class UServer_Base; @@ -1918,7 +1920,6 @@ public: // STREAM #ifdef U_STDCPP_ENABLE - istream& getline(istream& is, unsigned char delim = '\n'); friend U_EXPORT istream& operator>>(istream& is, UString& str); @@ -2244,6 +2245,20 @@ public: U_INTERNAL_ASSERT(invariant()) } + void appendData(const char* t, uint32_t tlen) + { + U_TRACE(0, "UString::appendData(%.*S,%u)", tlen, t, tlen) + + uint32_t sz = size(); + char* ptr = c_pointer(sz); + + U_MEMCPY(ptr, t, tlen); + + rep->_length = sz + tlen; + + U_INTERNAL_ASSERT(invariant()) + } + void appendDataQuoted(const char* t, uint32_t tlen) { U_TRACE(0, "UString::appendDataQuoted(%.*S,%u)", tlen, t, tlen) diff --git a/include/ulib/utility/hexdump.h b/include/ulib/utility/hexdump.h index 7f56d487..5986f832 100644 --- a/include/ulib/utility/hexdump.h +++ b/include/ulib/utility/hexdump.h @@ -18,6 +18,8 @@ #include +#define U_HEXDUMP(str) UHexDump::decode(U_CONSTANT_TO_PARAM(str)) + struct U_EXPORT UHexDump { static void encode(const char* s, uint32_t n, UString& buffer) @@ -44,6 +46,8 @@ struct U_EXPORT UHexDump { } static void decode(const UString& s, UString& buffer) { decode(U_STRING_TO_PARAM(s), buffer); } + + static UString decode(const char* s, uint32_t n) { UString tmp(U_CAPACITY); decode(s, n, tmp); return tmp; } }; #endif diff --git a/include/ulib/utility/string_ext.h b/include/ulib/utility/string_ext.h index a85e5a69..9d0ab6ef 100644 --- a/include/ulib/utility/string_ext.h +++ b/include/ulib/utility/string_ext.h @@ -256,6 +256,9 @@ public: static UString substitute(const char* s, uint32_t n, UVector& vec); static UString substitute(const UString& s, UVector& vec) { return substitute(U_STRING_TO_PARAM(s), vec); } + static UString substituteIds(const char* s, uint32_t n, UVector& vec); + static UString substituteIds(const UString& s, UVector& vec) { return substituteIds(U_STRING_TO_PARAM(s), vec); } + // ERASE static UString erase(const UString& s, char a) { return substitute(U_STRING_TO_PARAM(s), &a, 1, U_NULLPTR, 0); } diff --git a/ltmain.sh b/ltmain.sh index 2ad8be84..a736cf99 100644 --- a/ltmain.sh +++ b/ltmain.sh @@ -31,7 +31,7 @@ PROGRAM=libtool PACKAGE=libtool -VERSION="2.4.6 Debian-2.4.6-1" +VERSION="2.4.6 Debian-2.4.6-2" package_revision=2.4.6 @@ -1977,7 +1977,7 @@ func_version () # End: # Set a version string. -scriptversion='(GNU libtool) 2.4.6 Debian-2.4.6-1' +scriptversion='(GNU libtool) 2.4.6' # func_echo ARG... @@ -2068,7 +2068,7 @@ include the following information: compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) - version: $progname $scriptversion + version: $progname $scriptversion Debian-2.4.6-2 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` diff --git a/m4/ax_lib_postgresql.m4 b/m4/ax_lib_postgresql.m4 index b134fbf8..b3285369 100644 --- a/m4/ax_lib_postgresql.m4 +++ b/m4/ax_lib_postgresql.m4 @@ -100,7 +100,7 @@ AC_DEFUN([AX_LIB_POSTGRESQL], POSTGRESQL_CPPFLAGS="-I`$PG_CONFIG --includedir` -I`$PG_CONFIG --includedir-server`" POSTGRESQL_VERSION=`$PG_CONFIG --version | sed -e 's#PostgreSQL ##'` - if test -f "$postgresql_libdir/libpgport.a" -o -f "$postgresql_libdir/libpgport.so" -o -f "/usr/lib/libpgport.a" -o -f "/usr/lib/libpgport.so"; then + if test -f "$postgresql_libdir/libpgport.so" -o -f "/usr/lib/libpgport.so"; then POSTGRESQL_LIBS="-lpq -lpgport" else POSTGRESQL_LIBS="-lpq" diff --git a/src/ulib/Makefile.am b/src/ulib/Makefile.am index bf661781..657ee87b 100644 --- a/src/ulib/Makefile.am +++ b/src/ulib/Makefile.am @@ -38,7 +38,7 @@ SRC_CPP = internal/common.cpp internal/error.cpp \ net/client/smtp.cpp net/client/ftp.cpp net/client/pop3.cpp net/client/imap.cpp \ net/client/http.cpp net/client/client.cpp net/client/redis.cpp net/client/elasticsearch.cpp \ net/ipt_ACCOUNT.cpp \ - json/value.cpp \ + json/value.cpp serialize/flatbuffers.cpp \ query/query_parser.cpp event/event_time.cpp \ timeval.cpp timer.cpp notifier.cpp string.cpp file.cpp process.cpp file_config.cpp log.cpp \ options.cpp application.cpp cache.cpp date.cpp url.cpp tokenizer.cpp command.cpp diff --git a/src/ulib/Makefile.in b/src/ulib/Makefile.in index 3eb4671f..1eb5d3bf 100644 --- a/src/ulib/Makefile.in +++ b/src/ulib/Makefile.in @@ -263,21 +263,21 @@ am__lib@ULIB@_la_SOURCES_DIST = base/base.c base/base_error.c \ net/client/smtp.cpp net/client/ftp.cpp net/client/pop3.cpp \ net/client/imap.cpp net/client/http.cpp net/client/client.cpp \ net/client/redis.cpp net/client/elasticsearch.cpp \ - net/ipt_ACCOUNT.cpp json/value.cpp query/query_parser.cpp \ - event/event_time.cpp timeval.cpp timer.cpp notifier.cpp \ - string.cpp file.cpp process.cpp file_config.cpp log.cpp \ - options.cpp application.cpp cache.cpp date.cpp url.cpp \ - tokenizer.cpp command.cpp db/tdb.cpp net/client/mongodb.cpp \ - utility/http2.cpp internal/objectIO.cpp thread.cpp \ - debug/debug_common.cpp debug/trace.cpp debug/error_memory.cpp \ - debug/error_simulation.cpp debug/objectDB.cpp \ - internal/memory_pool.cpp zip/zip.cpp flex/flexer.cpp \ - flex/bison.cpp pcre/pcre.cpp ssl/certificate.cpp ssl/pkcs7.cpp \ - ssl/crl.cpp ssl/pkcs10.cpp net/client/twilio.cpp \ - ssl/mime/mime_pkcs7.cpp ssl/net/sslsocket.cpp \ - ssl/net/ssl_session.cpp utility/des3.cpp ssl/timestamp.cpp \ - ssh/net/sshsocket.cpp ldap/ldap.cpp curl/curl.cpp \ - xml/expat/attribute.cpp xml/expat/element.cpp \ + net/ipt_ACCOUNT.cpp json/value.cpp serialize/flatbuffers.cpp \ + query/query_parser.cpp event/event_time.cpp timeval.cpp \ + timer.cpp notifier.cpp string.cpp file.cpp process.cpp \ + file_config.cpp log.cpp options.cpp application.cpp cache.cpp \ + date.cpp url.cpp tokenizer.cpp command.cpp db/tdb.cpp \ + net/client/mongodb.cpp utility/http2.cpp internal/objectIO.cpp \ + thread.cpp debug/debug_common.cpp debug/trace.cpp \ + debug/error_memory.cpp debug/error_simulation.cpp \ + debug/objectDB.cpp internal/memory_pool.cpp zip/zip.cpp \ + flex/flexer.cpp flex/bison.cpp pcre/pcre.cpp \ + ssl/certificate.cpp ssl/pkcs7.cpp ssl/crl.cpp ssl/pkcs10.cpp \ + net/client/twilio.cpp ssl/mime/mime_pkcs7.cpp \ + ssl/net/sslsocket.cpp ssl/net/ssl_session.cpp utility/des3.cpp \ + ssl/timestamp.cpp ssh/net/sshsocket.cpp ldap/ldap.cpp \ + curl/curl.cpp xml/expat/attribute.cpp xml/expat/element.cpp \ xml/expat/xml_parser.cpp xml/expat/xml2txt.cpp \ xml/soap/soap_fault.cpp xml/soap/soap_gen_method.cpp \ xml/soap/soap_parser.cpp xml/soap/soap_encoder.cpp \ @@ -422,23 +422,24 @@ am__objects_67 = internal/common.lo internal/error.lo ui/dialog.lo \ net/client/ftp.lo net/client/pop3.lo net/client/imap.lo \ net/client/http.lo net/client/client.lo net/client/redis.lo \ net/client/elasticsearch.lo net/ipt_ACCOUNT.lo json/value.lo \ - query/query_parser.lo event/event_time.lo timeval.lo timer.lo \ - notifier.lo string.lo file.lo process.lo file_config.lo log.lo \ - options.lo application.lo cache.lo date.lo url.lo tokenizer.lo \ - command.lo $(am__objects_27) $(am__objects_28) \ - $(am__objects_29) $(am__objects_30) $(am__objects_31) \ - $(am__objects_32) $(am__objects_33) $(am__objects_34) \ - $(am__objects_35) $(am__objects_36) $(am__objects_37) \ - $(am__objects_38) $(am__objects_39) $(am__objects_40) \ - $(am__objects_41) $(am__objects_42) $(am__objects_43) \ - $(am__objects_44) $(am__objects_45) $(am__objects_46) \ - $(am__objects_47) $(am__objects_48) $(am__objects_49) \ - $(am__objects_50) $(am__objects_51) $(am__objects_52) \ - $(am__objects_53) $(am__objects_54) $(am__objects_55) \ - $(am__objects_56) $(am__objects_57) $(am__objects_58) \ - $(am__objects_59) $(am__objects_60) $(am__objects_61) \ - $(am__objects_62) $(am__objects_63) $(am__objects_64) \ - $(am__objects_65) $(am__objects_66) + serialize/flatbuffers.lo query/query_parser.lo \ + event/event_time.lo timeval.lo timer.lo notifier.lo string.lo \ + file.lo process.lo file_config.lo log.lo options.lo \ + application.lo cache.lo date.lo url.lo tokenizer.lo command.lo \ + $(am__objects_27) $(am__objects_28) $(am__objects_29) \ + $(am__objects_30) $(am__objects_31) $(am__objects_32) \ + $(am__objects_33) $(am__objects_34) $(am__objects_35) \ + $(am__objects_36) $(am__objects_37) $(am__objects_38) \ + $(am__objects_39) $(am__objects_40) $(am__objects_41) \ + $(am__objects_42) $(am__objects_43) $(am__objects_44) \ + $(am__objects_45) $(am__objects_46) $(am__objects_47) \ + $(am__objects_48) $(am__objects_49) $(am__objects_50) \ + $(am__objects_51) $(am__objects_52) $(am__objects_53) \ + $(am__objects_54) $(am__objects_55) $(am__objects_56) \ + $(am__objects_57) $(am__objects_58) $(am__objects_59) \ + $(am__objects_60) $(am__objects_61) $(am__objects_62) \ + $(am__objects_63) $(am__objects_64) $(am__objects_65) \ + $(am__objects_66) @FINAL_FALSE@am_lib@ULIB@_la_OBJECTS = $(am__objects_26) \ @FINAL_FALSE@ $(am__objects_67) @FINAL_TRUE@am_lib@ULIB@_la_OBJECTS = all_c.lo base/xxhash/xxhash.lo \ @@ -753,24 +754,24 @@ SRC_CPP = internal/common.cpp internal/error.cpp ui/dialog.cpp \ net/client/smtp.cpp net/client/ftp.cpp net/client/pop3.cpp \ net/client/imap.cpp net/client/http.cpp net/client/client.cpp \ net/client/redis.cpp net/client/elasticsearch.cpp \ - net/ipt_ACCOUNT.cpp json/value.cpp query/query_parser.cpp \ - event/event_time.cpp timeval.cpp timer.cpp notifier.cpp \ - string.cpp file.cpp process.cpp file_config.cpp log.cpp \ - options.cpp application.cpp cache.cpp date.cpp url.cpp \ - tokenizer.cpp command.cpp $(am__append_1) $(am__append_2) \ - $(am__append_3) $(am__append_4) $(am__append_5) \ - $(am__append_7) $(am__append_8) $(am__append_28) \ - $(am__append_31) $(am__append_33) $(am__append_34) \ - $(am__append_36) $(am__append_37) $(am__append_38) \ - $(am__append_39) $(am__append_40) $(am__append_41) \ - $(am__append_42) $(am__append_43) $(am__append_44) \ - $(am__append_45) $(am__append_47) $(am__append_48) \ - $(am__append_49) $(am__append_50) $(am__append_51) \ - $(am__append_52) $(am__append_53) $(am__append_54) \ - $(am__append_55) $(am__append_56) $(am__append_57) \ - $(am__append_58) $(am__append_59) $(am__append_60) \ - $(am__append_61) $(am__append_62) $(am__append_63) \ - $(am__append_64) $(am__append_65) + net/ipt_ACCOUNT.cpp json/value.cpp serialize/flatbuffers.cpp \ + query/query_parser.cpp event/event_time.cpp timeval.cpp \ + timer.cpp notifier.cpp string.cpp file.cpp process.cpp \ + file_config.cpp log.cpp options.cpp application.cpp cache.cpp \ + date.cpp url.cpp tokenizer.cpp command.cpp $(am__append_1) \ + $(am__append_2) $(am__append_3) $(am__append_4) \ + $(am__append_5) $(am__append_7) $(am__append_8) \ + $(am__append_28) $(am__append_31) $(am__append_33) \ + $(am__append_34) $(am__append_36) $(am__append_37) \ + $(am__append_38) $(am__append_39) $(am__append_40) \ + $(am__append_41) $(am__append_42) $(am__append_43) \ + $(am__append_44) $(am__append_45) $(am__append_47) \ + $(am__append_48) $(am__append_49) $(am__append_50) \ + $(am__append_51) $(am__append_52) $(am__append_53) \ + $(am__append_54) $(am__append_55) $(am__append_56) \ + $(am__append_57) $(am__append_58) $(am__append_59) \ + $(am__append_60) $(am__append_61) $(am__append_62) \ + $(am__append_63) $(am__append_64) $(am__append_65) #lib@ULIB@_la_CXXFLAGS = lib@ULIB@_la_LDFLAGS = @ULIB_LIBS@ -version-info 1:0:0 -release \ @@ -1178,6 +1179,14 @@ json/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) json/$(DEPDIR) @: > json/$(DEPDIR)/$(am__dirstamp) json/value.lo: json/$(am__dirstamp) json/$(DEPDIR)/$(am__dirstamp) +serialize/$(am__dirstamp): + @$(MKDIR_P) serialize + @: > serialize/$(am__dirstamp) +serialize/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) serialize/$(DEPDIR) + @: > serialize/$(DEPDIR)/$(am__dirstamp) +serialize/flatbuffers.lo: serialize/$(am__dirstamp) \ + serialize/$(DEPDIR)/$(am__dirstamp) query/$(am__dirstamp): @$(MKDIR_P) query @: > query/$(am__dirstamp) @@ -1490,6 +1499,8 @@ mostlyclean-compile: -rm -f query/*.lo -rm -f replace/*.$(OBJEXT) -rm -f replace/*.lo + -rm -f serialize/*.$(OBJEXT) + -rm -f serialize/*.lo -rm -f ssh/net/*.$(OBJEXT) -rm -f ssh/net/*.lo -rm -f ssl/*.$(OBJEXT) @@ -1654,6 +1665,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@replace/$(DEPDIR)/strndup.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@replace/$(DEPDIR)/strptime.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@replace/$(DEPDIR)/timegm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@serialize/$(DEPDIR)/flatbuffers.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ssh/net/$(DEPDIR)/sshsocket.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ssl/$(DEPDIR)/certificate.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ssl/$(DEPDIR)/crl.Plo@am__quote@ @@ -1781,6 +1793,7 @@ clean-libtool: -rm -rf pcre/.libs pcre/_libs -rm -rf query/.libs query/_libs -rm -rf replace/.libs replace/_libs + -rm -rf serialize/.libs serialize/_libs -rm -rf ssh/net/.libs ssh/net/_libs -rm -rf ssl/.libs ssl/_libs -rm -rf ssl/mime/.libs ssl/mime/_libs @@ -1955,6 +1968,8 @@ distclean-generic: -rm -f query/$(am__dirstamp) -rm -f replace/$(DEPDIR)/$(am__dirstamp) -rm -f replace/$(am__dirstamp) + -rm -f serialize/$(DEPDIR)/$(am__dirstamp) + -rm -f serialize/$(am__dirstamp) -rm -f ssh/net/$(DEPDIR)/$(am__dirstamp) -rm -f ssh/net/$(am__dirstamp) -rm -f ssl/$(DEPDIR)/$(am__dirstamp) @@ -1986,7 +2001,7 @@ clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ mostlyclean-am distclean: distclean-am - -rm -rf ./$(DEPDIR) base/$(DEPDIR) base/apex/$(DEPDIR) base/coder/$(DEPDIR) base/miniz/$(DEPDIR) base/ssl/$(DEPDIR) base/win32/$(DEPDIR) base/xxhash/$(DEPDIR) base/zip/$(DEPDIR) container/$(DEPDIR) curl/$(DEPDIR) db/$(DEPDIR) dbi/$(DEPDIR) debug/$(DEPDIR) dynamic/$(DEPDIR) event/$(DEPDIR) flex/$(DEPDIR) internal/$(DEPDIR) json/$(DEPDIR) ldap/$(DEPDIR) lemon/$(DEPDIR) libevent/$(DEPDIR) magic/$(DEPDIR) mime/$(DEPDIR) net/$(DEPDIR) net/client/$(DEPDIR) net/rpc/$(DEPDIR) net/server/$(DEPDIR) net/server/plugin/$(DEPDIR) net/server/plugin/mod_geoip/$(DEPDIR) net/server/plugin/mod_shib/$(DEPDIR) orm/$(DEPDIR) orm/driver/$(DEPDIR) pcre/$(DEPDIR) query/$(DEPDIR) replace/$(DEPDIR) ssh/net/$(DEPDIR) ssl/$(DEPDIR) ssl/mime/$(DEPDIR) ssl/net/$(DEPDIR) ui/$(DEPDIR) utility/$(DEPDIR) xml/expat/$(DEPDIR) xml/libxml2/$(DEPDIR) xml/soap/$(DEPDIR) zip/$(DEPDIR) + -rm -rf ./$(DEPDIR) base/$(DEPDIR) base/apex/$(DEPDIR) base/coder/$(DEPDIR) base/miniz/$(DEPDIR) base/ssl/$(DEPDIR) base/win32/$(DEPDIR) base/xxhash/$(DEPDIR) base/zip/$(DEPDIR) container/$(DEPDIR) curl/$(DEPDIR) db/$(DEPDIR) dbi/$(DEPDIR) debug/$(DEPDIR) dynamic/$(DEPDIR) event/$(DEPDIR) flex/$(DEPDIR) internal/$(DEPDIR) json/$(DEPDIR) ldap/$(DEPDIR) lemon/$(DEPDIR) libevent/$(DEPDIR) magic/$(DEPDIR) mime/$(DEPDIR) net/$(DEPDIR) net/client/$(DEPDIR) net/rpc/$(DEPDIR) net/server/$(DEPDIR) net/server/plugin/$(DEPDIR) net/server/plugin/mod_geoip/$(DEPDIR) net/server/plugin/mod_shib/$(DEPDIR) orm/$(DEPDIR) orm/driver/$(DEPDIR) pcre/$(DEPDIR) query/$(DEPDIR) replace/$(DEPDIR) serialize/$(DEPDIR) ssh/net/$(DEPDIR) ssl/$(DEPDIR) ssl/mime/$(DEPDIR) ssl/net/$(DEPDIR) ui/$(DEPDIR) utility/$(DEPDIR) xml/expat/$(DEPDIR) xml/libxml2/$(DEPDIR) xml/soap/$(DEPDIR) zip/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic @@ -2031,7 +2046,7 @@ install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) base/$(DEPDIR) base/apex/$(DEPDIR) base/coder/$(DEPDIR) base/miniz/$(DEPDIR) base/ssl/$(DEPDIR) base/win32/$(DEPDIR) base/xxhash/$(DEPDIR) base/zip/$(DEPDIR) container/$(DEPDIR) curl/$(DEPDIR) db/$(DEPDIR) dbi/$(DEPDIR) debug/$(DEPDIR) dynamic/$(DEPDIR) event/$(DEPDIR) flex/$(DEPDIR) internal/$(DEPDIR) json/$(DEPDIR) ldap/$(DEPDIR) lemon/$(DEPDIR) libevent/$(DEPDIR) magic/$(DEPDIR) mime/$(DEPDIR) net/$(DEPDIR) net/client/$(DEPDIR) net/rpc/$(DEPDIR) net/server/$(DEPDIR) net/server/plugin/$(DEPDIR) net/server/plugin/mod_geoip/$(DEPDIR) net/server/plugin/mod_shib/$(DEPDIR) orm/$(DEPDIR) orm/driver/$(DEPDIR) pcre/$(DEPDIR) query/$(DEPDIR) replace/$(DEPDIR) ssh/net/$(DEPDIR) ssl/$(DEPDIR) ssl/mime/$(DEPDIR) ssl/net/$(DEPDIR) ui/$(DEPDIR) utility/$(DEPDIR) xml/expat/$(DEPDIR) xml/libxml2/$(DEPDIR) xml/soap/$(DEPDIR) zip/$(DEPDIR) + -rm -rf ./$(DEPDIR) base/$(DEPDIR) base/apex/$(DEPDIR) base/coder/$(DEPDIR) base/miniz/$(DEPDIR) base/ssl/$(DEPDIR) base/win32/$(DEPDIR) base/xxhash/$(DEPDIR) base/zip/$(DEPDIR) container/$(DEPDIR) curl/$(DEPDIR) db/$(DEPDIR) dbi/$(DEPDIR) debug/$(DEPDIR) dynamic/$(DEPDIR) event/$(DEPDIR) flex/$(DEPDIR) internal/$(DEPDIR) json/$(DEPDIR) ldap/$(DEPDIR) lemon/$(DEPDIR) libevent/$(DEPDIR) magic/$(DEPDIR) mime/$(DEPDIR) net/$(DEPDIR) net/client/$(DEPDIR) net/rpc/$(DEPDIR) net/server/$(DEPDIR) net/server/plugin/$(DEPDIR) net/server/plugin/mod_geoip/$(DEPDIR) net/server/plugin/mod_shib/$(DEPDIR) orm/$(DEPDIR) orm/driver/$(DEPDIR) pcre/$(DEPDIR) query/$(DEPDIR) replace/$(DEPDIR) serialize/$(DEPDIR) ssh/net/$(DEPDIR) ssl/$(DEPDIR) ssl/mime/$(DEPDIR) ssl/net/$(DEPDIR) ui/$(DEPDIR) utility/$(DEPDIR) xml/expat/$(DEPDIR) xml/libxml2/$(DEPDIR) xml/soap/$(DEPDIR) zip/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/src/ulib/all_cpp.cpp b/src/ulib/all_cpp.cpp index 53e2576d..9163bb30 100644 --- a/src/ulib/all_cpp.cpp +++ b/src/ulib/all_cpp.cpp @@ -51,6 +51,7 @@ #include "utility/string_ext.cpp" #include "utility/socket_ext.cpp" #include "utility/data_session.cpp" +#include "serialize/flatbuffers.cpp" #include "lemon/expression.cpp" #include "dynamic/dynamic.cpp" #include "dynamic/plugin.cpp" diff --git a/src/ulib/base/base.c b/src/ulib/base/base.c index ee0e92bf..b7cb0eab 100644 --- a/src/ulib/base/base.c +++ b/src/ulib/base/base.c @@ -1970,11 +1970,12 @@ empty: u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16('"','"')); n = 0; remaining = buffer_size - (bp-buffer); - if ((flags & ALT) != 0) /* NB: # -> force print of all binary string (compatibly with buffer size)... */ + if ((flags & ALT) != 0) /* NB: # -> force print of all binary string (compatible with buffer size)... */ { remaining >>= 1; - if (u__isprint(*cp) == false && + if (ch != 'V' && + u__isprint(*cp) == false && u__isspace(*cp) == false) { sign = 1; /* we want to print buffer as exadecimal... */ @@ -1998,7 +1999,7 @@ empty: u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16('"','"')); else { if (c == '\0' && - (flags & ALT) == 0) /* NB: # -> force print of all binary string (compatibly with buffer size)... */ + (flags & ALT) == 0) /* NB: # -> force print of all binary string (compatible with buffer size)... */ { break; } diff --git a/src/ulib/internal/common.cpp b/src/ulib/internal/common.cpp index b7980717..6263062f 100644 --- a/src/ulib/internal/common.cpp +++ b/src/ulib/internal/common.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #ifndef HAVE_POLL_H # include @@ -158,8 +159,8 @@ void ULib::init(char** argv, const char* mempool) // allocation from memory pool -#if defined(ENABLE_MEMPOOL) // check if we want some preallocation for memory pool - const char* ptr = (mempool ? (UValue::jsonParseFlags = 2, mempool) : U_SYSCALL(getenv, "%S", "UMEMPOOL")); // start from 1... (Ex: 768,768,0,1536,2085,0,0,0,121) +#if defined(ENABLE_MEMPOOL) // check if we want some preallocation for memory pool - start from 1... (Ex: 768,768,0,1536,2085,0,0,0,121) + const char* ptr = (mempool ? (UValue::jsonParseFlags = 2, mempool) : U_SYSCALL(getenv, "%S", "UMEMPOOL")); // coverity[tainted_scalar] if ( ptr && @@ -191,6 +192,9 @@ void ULib::init(char** argv, const char* mempool) # endif #endif + UFlatBuffer::setStack((uint8_t*)u_err_buffer, 256); + UFlatBuffer::setBuffer((uint8_t*)u_buffer, U_BUFFER_SIZE); + UString::ptrbuf = UString::appbuf = (char*)UMemoryPool::pop(U_SIZE_TO_STACK_INDEX(1024)); UFile::cwd_save = (char*)UMemoryPool::pop(U_SIZE_TO_STACK_INDEX(1024)); diff --git a/src/ulib/json/value.cpp b/src/ulib/json/value.cpp index 6cc65e64..b02bd9c4 100644 --- a/src/ulib/json/value.cpp +++ b/src/ulib/json/value.cpp @@ -20,6 +20,7 @@ int UValue::jsonParseFlags; char* UValue::pstringify; uint32_t UValue::size; UValue::jval UValue::o; +UFlatBuffer* UValue::pfb; UValue::parser_stack_data UValue::sd[U_JSON_PARSE_STACK_SIZE]; #ifdef DEBUG @@ -111,7 +112,7 @@ void UValue::clear() 0,/* 9 */ }; - uint32_t type = getTag(); + uint8_t type = getTag(); U_DUMP("dispatch_table[(%u,%S)] = %d", type, getDataTypeDescription(type), dispatch_table[type]) @@ -181,9 +182,9 @@ case_object: } } -__pure UValue* UValue::at(uint32_t pos) const +__pure UValue* UValue::at(uint32_t idx) const { - U_TRACE(0, "UValue::at(%u)", pos) + U_TRACE(0, "UValue::at(%u)", idx) if (getTag() == U_ARRAY_VALUE) { @@ -194,7 +195,7 @@ __pure UValue* UValue::at(uint32_t pos) const { U_DUMP("element = %p element->next = %p element->type = (%u,%S)", element, element->next, element->getTag(), getDataTypeDescription(element->getTag())) - if (i++ == pos) U_RETURN_POINTER(element, UValue); + if (i++ == idx) U_RETURN_POINTER(element, UValue); element = element->next; } @@ -425,7 +426,7 @@ void UValue::stringify() const (int)((char*)&&case_null-(char*)&&case_double) }; - uint32_t type = getTag(); + uint8_t type = getTag(); U_DUMP("dispatch_table[(%u,%S)] = %d", type, getDataTypeDescription(type), dispatch_table[type]) @@ -437,12 +438,12 @@ case_double: return; case_int: - pstringify = u_num2str32s(getInt(), pstringify); + pstringify = u_num2str64s(getInt64(), pstringify); return; case_uint: - pstringify = u_num2str32(getUInt(), pstringify); + pstringify = u_num2str64(getUInt64(), pstringify); return; @@ -541,24 +542,24 @@ void UValue::prettify(uint32_t indent) const (int)((char*)&&case_null-(char*)&&case_double) }; - uint32_t type = getTag(); + uint8_t type = getTag(); U_DUMP("dispatch_table[(%u,%S)] = %d", type, getDataTypeDescription(type), dispatch_table[type]) goto *((char*)&&case_double + dispatch_table[type]); case_double: - pstringify = u_dtoa(value.real, pstringify); + pstringify = u_dtoa(value.real, pstringify); return; case_int: - pstringify = u_num2str32s(getInt(), pstringify); + pstringify = u_num2str64s(getInt64(), pstringify); return; case_uint: - pstringify = u_num2str32(getUInt(), pstringify); + pstringify = u_num2str64(getUInt64(), pstringify); return; @@ -677,6 +678,371 @@ case_null: pstringify += U_CONSTANT_SIZE("null"); } +void UValue::toFlatBufferFromJSON() const +{ + U_TRACE_NO_PARAM(0, "UValue::toFlatBufferFromJSON()") + + static const int dispatch_table[] = { + 0,/* 0 */ + (int)((char*)&&case_int-(char*)&&case_double), + (int)((char*)&&case_uint-(char*)&&case_double), + (int)((char*)&&case_true-(char*)&&case_double), + (int)((char*)&&case_false-(char*)&&case_double), + (int)((char*)&&case_string-(char*)&&case_double), + (int)((char*)&&case_utf-(char*)&&case_double), + (int)((char*)&&case_array-(char*)&&case_double), + (int)((char*)&&case_object-(char*)&&case_double), + (int)((char*)&&case_null-(char*)&&case_double) + }; + + uint32_t n; + UStringRep* rep; + uint8_t type = getTag(); + + U_DUMP("dispatch_table[(%u,%S)] = %d", type, getDataTypeDescription(type), dispatch_table[type]) + + goto *((char*)&&case_double + dispatch_table[type]); + +case_double: + pfb->Add(value.real); + + return; + +case_int: + pfb->Int(getInt64()); + + return; + +case_uint: + pfb->UInt(getUInt64()); + + return; + +case_true: + pfb->Add(true); + + return; + +case_false: + pfb->Add(false); + + return; + +case_string: +case_utf: + rep = (UStringRep*)getPayload(); + + n = rep->size(); + + pfb->Add(rep->data(), n); + + pstringify += UFlatBuffer::GetByteWidth(n) + n; + + return; + +case_array: + { + UValue* element = toNode(); + + if (element == U_NULLPTR) pfb->AddVectorEmpty(); + else + { + bool typed, fixed; + uint32_t start = pfb->StartVector(); + uint8_t old_type = element->getTag(); + + n = 1; + fixed = ((typed = (isArrayOrObject(old_type) == false)) ? isNumeric(old_type) : false); + +l1: U_DUMP("element = %p element->next = %p element->type = (%u,%S)", element, element->next, element->getTag(), getDataTypeDescription(element->getTag())) + + element->toFlatBufferFromJSON(); + + if ((element = element->next)) + { + U_INTERNAL_DUMP("typed = %b fixed = %b old_type = %u n = %u", typed, fixed, old_type, n) + + if (typed) + { + if (element->getTag() == old_type) + { + if (fixed && + ++n > 4) + { + fixed = false; + } + } + else if (isBool(old_type) == false || + element->isBool() == false) + { + typed = fixed = false; + } + } + + goto l1; + } + + pfb->EndVector(start, typed, fixed); + } + + pstringify = (char*)pfb->getPointer(); + + return; + } + +case_object: + { + UValue* element = toNode(); + + if (element == U_NULLPTR) pfb->AddMapEmpty(); + else + { + uint32_t start = pfb->StartMap(); + +l2: U_DUMP("element = %p element->next = %p element->type = (%u,%S)", element, element->next, element->getTag(), getDataTypeDescription(element->getTag())) + + rep = (UStringRep*)u_getPayload(element->pkey.ival); + + pfb->Key(U_STRING_TO_PARAM(*rep)); + + element->toFlatBufferFromJSON(); + + if ((element = element->next)) goto l2; + + pfb->EndMap(start); + } + + pstringify = (char*)pfb->getPointer(); + + return; + } + +case_null: + pfb->Add(); +} + +void UValue::fromFlatBufferToJSON(UFlatBuffer& fb) +{ + U_TRACE(0, "UValue::fromFlatBufferToJSON(%p)", &fb) + + uint8_t type = fb.GetType(); + + U_DUMP("fb.GetType() = (%u,%S)", type, UFlatBuffer::getTypeDescription(type)) + + switch (type) + { + case UFlatBufferValue::TYPE_NULL: setNull(); break; + case UFlatBufferValue::TYPE_BOOL: setBool( fb.AsBool()); break; + case UFlatBufferValue::TYPE_INT: setInt64( fb.AsInt64()); break; + case UFlatBufferValue::TYPE_UINT: setUInt64(fb.AsUInt64()); break; + case UFlatBufferValue::TYPE_INDIRECT_INT: setInt64( fb.AsIndirectInt64()); break; + case UFlatBufferValue::TYPE_INDIRECT_UINT: setUInt64(fb.AsIndirectUInt64()); break; + case UFlatBufferValue::TYPE_FLOAT: setDouble(fb.AsDouble()); break; + case UFlatBufferValue::TYPE_INDIRECT_FLOAT: setDouble(fb.AsIndirectDouble()); break; + + case UFlatBufferValue::TYPE_STRING: + { + uint8_t* str = fb.Indirect(); + + addString((const char*)str, fb.getSize(str)); + } + break; + + case UFlatBufferValue::TYPE_VECTOR: + case UFlatBufferValue::TYPE_VECTOR_STRING: + case UFlatBufferValue::TYPE_VECTOR_INT: + case UFlatBufferValue::TYPE_VECTOR_UINT: + case UFlatBufferValue::TYPE_VECTOR_FLOAT: + case UFlatBufferValue::TYPE_VECTOR_INT2: + case UFlatBufferValue::TYPE_VECTOR_UINT2: + case UFlatBufferValue::TYPE_VECTOR_FLOAT2: + case UFlatBufferValue::TYPE_VECTOR_INT3: + case UFlatBufferValue::TYPE_VECTOR_UINT3: + case UFlatBufferValue::TYPE_VECTOR_FLOAT3: + case UFlatBufferValue::TYPE_VECTOR_INT4: + case UFlatBufferValue::TYPE_VECTOR_UINT4: + case UFlatBufferValue::TYPE_VECTOR_FLOAT4: + { + UFlatBuffer vec; + uint32_t i = 0, n; + + initStackParser(false); + + switch (type) + { + case UFlatBufferValue::TYPE_VECTOR: + { + UFlatBuffer fbb; + + fb.AsVector(vec); + + for (n = vec.GetSize(); i < n; ++i) + { + vec.AsVectorGet(i, fbb); + + fromFlatBufferToJSON(fbb); + } + } + break; + + case UFlatBufferValue::TYPE_VECTOR_STRING: + { + fb.AsTypedVector(vec); + + for (n = vec.GetSize(); i < n; ++i) addStringParser(vec.AsTypedOrFixedVectorGet(i)); + } + break; + + default: + { + fb.AsFixedTypedVector(vec); + + switch (type) + { + case UFlatBufferValue::TYPE_VECTOR_INT4: setInt64( vec.AsTypedOrFixedVectorGet< int64_t>(i++)); sd[pos].tails = insertAfter(sd[pos].tails, o.ival); /* FALLTHRU */ + case UFlatBufferValue::TYPE_VECTOR_INT3: setInt64( vec.AsTypedOrFixedVectorGet< int64_t>(i++)); sd[pos].tails = insertAfter(sd[pos].tails, o.ival); /* FALLTHRU */ + case UFlatBufferValue::TYPE_VECTOR_INT2: setInt64( vec.AsTypedOrFixedVectorGet< int64_t>(i++)); sd[pos].tails = insertAfter(sd[pos].tails, o.ival); /* FALLTHRU */ + case UFlatBufferValue::TYPE_VECTOR_INT: setInt64( vec.AsTypedOrFixedVectorGet< int64_t>(i++)); sd[pos].tails = insertAfter(sd[pos].tails, o.ival); break; + case UFlatBufferValue::TYPE_VECTOR_UINT4: setUInt64(vec.AsTypedOrFixedVectorGet(i++)); sd[pos].tails = insertAfter(sd[pos].tails, o.ival); /* FALLTHRU */ + case UFlatBufferValue::TYPE_VECTOR_UINT3: setUInt64(vec.AsTypedOrFixedVectorGet(i++)); sd[pos].tails = insertAfter(sd[pos].tails, o.ival); /* FALLTHRU */ + case UFlatBufferValue::TYPE_VECTOR_UINT2: setUInt64(vec.AsTypedOrFixedVectorGet(i++)); sd[pos].tails = insertAfter(sd[pos].tails, o.ival); /* FALLTHRU */ + case UFlatBufferValue::TYPE_VECTOR_UINT: setUInt64(vec.AsTypedOrFixedVectorGet(i++)); sd[pos].tails = insertAfter(sd[pos].tails, o.ival); break; + case UFlatBufferValue::TYPE_VECTOR_FLOAT4: setDouble(vec.AsTypedOrFixedVectorGet( i++)); sd[pos].tails = insertAfter(sd[pos].tails, o.ival); /* FALLTHRU */ + case UFlatBufferValue::TYPE_VECTOR_FLOAT3: setDouble(vec.AsTypedOrFixedVectorGet( i++)); sd[pos].tails = insertAfter(sd[pos].tails, o.ival); /* FALLTHRU */ + case UFlatBufferValue::TYPE_VECTOR_FLOAT2: setDouble(vec.AsTypedOrFixedVectorGet( i++)); sd[pos].tails = insertAfter(sd[pos].tails, o.ival); /* FALLTHRU */ + case UFlatBufferValue::TYPE_VECTOR_FLOAT: setDouble(vec.AsTypedOrFixedVectorGet( i++)); sd[pos].tails = insertAfter(sd[pos].tails, o.ival); + break; + } + } + break; + } + + U_INTERNAL_ASSERT_MAJOR(i, 0) + + setArray(); + } + break; + + case UFlatBufferValue::TYPE_VECTOR_BOOL: + { + UFlatBuffer vec; + + fb.AsTypedVector(vec); + + uint32_t n = vec.GetSize(); + + if (n == 0) setArrayEmpty(); + else + { + initStackParser(false); + + for (uint32_t i = 0; i < n; ++i) + { + setBool(vec.AsTypedOrFixedVectorGet(i)); + + nextParser(); + } + + setArray(); + } + } + break; + + case UFlatBufferValue::TYPE_MAP: + { + UFlatBuffer map; + + fb.AsMap(map); + + uint32_t n = map.GetSize(); + + if (n == 0) setObjectEmpty(); + else + { + UFlatBuffer keys, values, fbb; + + map.AsMapGetKeys(keys); + map.AsMapGetValues(values); + + initStackParser(true); + + for (uint32_t i = 0; i < n; ++i) + { + addStringParser(keys.AsTypedOrFixedVectorGet(i)); + + values.AsVectorGet(i, fbb); + + fromFlatBufferToJSON(fbb); + } + + setObject(); + } + } + break; + + default: + { + U_INTERNAL_ASSERT(false) + } + break; + } + + if (pos != -1) nextParser(); +} + +void UValue::toFlatBuffer(UFlatBuffer& fb, UString& result) const +{ + U_TRACE(0, "UValue::toFlatBuffer(%p,%p)", &fb, &result) + + U_INTERNAL_DUMP("size = %u UFlatBuffer::getBufferMax() = %u UFlatBuffer::getStackMax() = %u", size, UFlatBuffer::getBufferMax(), UFlatBuffer::getStackMax()) + + uint8_t* prev_stack; + uint8_t* prev_buffer; + uint8_t stack[64 * 1024]; + uint32_t end, prev_stack_size, prev_buffer_size; + bool breset1 = (size > UFlatBuffer::getBufferMax()), + breset2 = (sizeof(stack) > UFlatBuffer::getStackMax()); + + // buffer to serialize json + + if (breset1 == false) pstringify = (char*)UFlatBuffer::getBuffer(); + else + { + prev_buffer = UFlatBuffer::getBuffer(); + prev_buffer_size = UFlatBuffer::getBufferMax(); + + (void) result.reserve(size+100U); + + UFlatBuffer::setBuffer((uint8_t*)(pstringify = result.data()), result.capacity()); + } + + if (breset2) + { + U_INTERNAL_ASSERT_MINOR(size, sizeof(stack)) + + prev_stack = UFlatBuffer::getStack(); + prev_stack_size = UFlatBuffer::getStackMax(); + + UFlatBuffer::setStack(stack, sizeof(stack)); + } + + (pfb = &fb)->StartBuild(); + + toFlatBufferFromJSON(); + + end = fb.EndBuild(); + + if (breset1 == false) result = fb.getResult(); + else + { + result.size_adjust(end); + + UFlatBuffer::setBuffer(prev_buffer, prev_buffer_size); + } + + if (breset2) UFlatBuffer::setStack(prev_stack, prev_stack_size); +} + bool UValue::parse(const UString& document) { U_TRACE(0, "UValue::parse(%V)", document.rep) @@ -786,6 +1152,7 @@ bool UValue::parse(const UString& document) #endif double val; + uint8_t type; int gexponent; const char* p; unsigned char c; @@ -794,7 +1161,7 @@ bool UValue::parse(const UString& document) uint64_t integerPart; const char* s = document.data(); const char* end = s + (size = document.size()); - uint32_t type, sz, significandDigit, decimalDigit, exponent; + uint32_t sz, significandDigit, decimalDigit, exponent; bool minus = false, colon = false, comma = false, separator = true; initParser(); @@ -882,7 +1249,7 @@ dquote_assign: { U_NEW(UStringRep, rep, UStringRep(start, sz)); - o.ival = getValue(type, rep); + setValue(type, rep); } else { @@ -890,14 +1257,14 @@ dquote_assign: str.hold(); - o.ival = getValue(type, str.rep); + setValue(type, str.rep); } } else { UStringRep::string_rep_null->hold(); - o.ival = getValue(U_STRING_VALUE, UStringRep::string_rep_null); + setValue(U_STRING_VALUE, UStringRep::string_rep_null); } goto next; @@ -985,7 +1352,7 @@ case_zero: { zero: if (c == '.') goto case_number; - o.ival = getValue(U_UINT_VALUE, U_NULLPTR); + o.ival = u_getValue(U_UINT_VALUE, U_NULLPTR); goto next; } @@ -1162,37 +1529,30 @@ exp: if (u__issign((c = *++s))) ++s; noreal: U_INTERNAL_ASSERT_DIFFERS(*start, '.') + if (integerPart > U_VALUE_PAYLOAD_MASK) // U_VALUE_PAYLOAD_MASK => 140737488355327 (15 digit) - UINT_MAX => 4294967295 (9 digit) + { + val = (double)integerPart; + + goto mreal1; + } + if (minus == false) { - if (integerPart > UINT_MAX) // UINT_MAX => 4294967295 (9 digit) - { - val = (double)integerPart; + setValue(U_UINT_VALUE, (void*)integerPart); - goto mreal1; - } + U_INTERNAL_DUMP("value(%.*S) = %llu", s-start, start, integerPart) - o.ival = getValue(U_UINT_VALUE, (void*)(integerPart & 0x00000000FFFFFFFFULL)); - - U_INTERNAL_DUMP("value(%.*S) = %u", s-start, start, (uint32_t)integerPart) - - U_INTERNAL_ASSERT_EQUALS((uint32_t)integerPart, ::strtoul(start, U_NULLPTR, 10)) + U_INTERNAL_ASSERT_EQUALS(integerPart, ::strtoull(start, U_NULLPTR, 10)) } else { - if (integerPart > 2147483648ULL) // INT_MIN => -2147483648 (9 digit) - { - val = (double)integerPart; - - goto mreal1; - } - minus = false; - o.ival = getValue(U_INT_VALUE, (void*)(-integerPart & 0x00000000FFFFFFFFULL)); + setValue(U_INT_VALUE, (void*)integerPart); - U_INTERNAL_DUMP("value(%.*S) = %d", s-(start-1), start-1, -(int32_t)integerPart) + U_INTERNAL_DUMP("value(%.*S) = %lld", s-(start-1), start-1, -(int64_t)integerPart) - U_INTERNAL_ASSERT_EQUALS(-(int32_t)integerPart, ::strtol(start-1, U_NULLPTR, 10)) + U_INTERNAL_ASSERT_EQUALS(-(int64_t)integerPart, ::strtoll(start-1, U_NULLPTR, 10)) } goto next; @@ -1261,13 +1621,7 @@ case_svector: if (*s != ']') { - ++pos; - - U_INTERNAL_ASSERT_MINOR(pos, U_JSON_PARSE_STACK_SIZE) - - sd[pos].keys = 0; - sd[pos].tails = U_NULLPTR; - sd[pos].obj = false; + initStackParser(false); comma = false; separator = true; @@ -1277,7 +1631,7 @@ case_svector: ++s; - o.ival = listToValue(U_ARRAY_VALUE, U_NULLPTR); + setArrayEmpty(); goto next; @@ -1291,14 +1645,14 @@ case_evector: break; } - o.ival = listToValue(U_ARRAY_VALUE, sd[pos--].tails); + setArray(); goto next; case_false: if (u_get_unalignedp32(s) == U_MULTICHAR_CONSTANT32('a','l','s','e')) { - o.ival = getValue(U_FALSE_VALUE, U_NULLPTR); + setBool(false); s = start+U_CONSTANT_SIZE("false"); @@ -1310,7 +1664,7 @@ case_false: case_null: if (u_get_unalignedp32(start) == U_MULTICHAR_CONSTANT32('n','u','l','l')) { - o.ival = getValue(U_NULL_VALUE, U_NULLPTR); + setNull(); s = start+U_CONSTANT_SIZE("null"); @@ -1322,7 +1676,7 @@ case_null: case_true: if (u_get_unalignedp32(start) == U_MULTICHAR_CONSTANT32('t','r','u','e')) { - o.ival = getValue(U_TRUE_VALUE, U_NULLPTR); + setBool(true); s = start+U_CONSTANT_SIZE("true"); @@ -1336,13 +1690,7 @@ case_sobject: if (*s != '}') { - ++pos; - - U_INTERNAL_ASSERT_MINOR(pos, U_JSON_PARSE_STACK_SIZE) - - sd[pos].keys = 0; - sd[pos].tails = U_NULLPTR; - sd[pos].obj = true; + initStackParser(true); comma = false; separator = true; @@ -1352,7 +1700,7 @@ case_sobject: ++s; - o.ival = listToValue(U_OBJECT_VALUE, U_NULLPTR); + setObjectEmpty(); goto next; @@ -1367,7 +1715,7 @@ case_eobject: break; } - o.ival = listToValue(U_OBJECT_VALUE, sd[pos--].tails); + setObject(); next: U_INTERNAL_DUMP("next: comma = %b pos = %d colon = %b separator = %b s = %.10S", comma, pos, colon, separator, s) @@ -1390,7 +1738,7 @@ next: U_INTERNAL_DUMP("next: comma = %b pos = %d colon = %b separator = %b s = % comma = separator = false; - U_DUMP("sd[%d].obj = (%d,%S) sd[%d].tails = %p", pos, (sd[pos].obj ? U_OBJECT_VALUE : U_ARRAY_VALUE), + U_DUMP("sd[%u].obj = (%d,%S) sd[%u].tails = %p", pos, (sd[pos].obj ? U_OBJECT_VALUE : U_ARRAY_VALUE), getDataTypeDescription((sd[pos].obj ? U_OBJECT_VALUE : U_ARRAY_VALUE)), pos, sd[pos].tails) if (sd[pos].obj == false) sd[pos].tails = insertAfter(sd[pos].tails, o.ival); @@ -1447,11 +1795,11 @@ void UValue::nextParser() { U_TRACE_NO_PARAM(0, "UValue::nextParser()") - U_INTERNAL_DUMP("UValue::pos = %d", UValue::pos) + U_INTERNAL_DUMP("pos = %d", pos) - U_INTERNAL_ASSERT_DIFFERS(UValue::pos, -1) + U_INTERNAL_ASSERT_DIFFERS(pos, -1) - U_DUMP("sd[%d].obj = (%d,%S) sd[%d].tails = %p sd[%d].keys = %#llx", pos, (sd[pos].obj ? U_OBJECT_VALUE : U_ARRAY_VALUE), + U_DUMP("sd[%u].obj = (%d,%S) sd[%u].tails = %p sd[%u].keys = %#llx", pos, (sd[pos].obj ? U_OBJECT_VALUE : U_ARRAY_VALUE), getDataTypeDescription((sd[pos].obj ? U_OBJECT_VALUE : U_ARRAY_VALUE)), pos, sd[pos].tails, pos, sd[pos].keys) if (sd[pos].obj == false) sd[pos].tails = insertAfter(sd[pos].tails, o.ival); @@ -1461,7 +1809,7 @@ void UValue::nextParser() { sd[pos].keys = o.ival; - U_INTERNAL_DUMP("sd[%d].keys = %V", pos, u_getPayload(sd[pos].keys)) + U_INTERNAL_DUMP("sd[%u].keys = %V", pos, u_getPayload(sd[pos].keys)) return; } @@ -2169,13 +2517,13 @@ bool UValue::jfind(const UString& json, const char* query, uint32_t query_len, U U_ASSERT(result.empty()) U_INTERNAL_ASSERT(u_is_quoted(query, query_len)) - uint32_t pos = json.find(query, 0, query_len); + uint32_t idx = json.find(query, 0, query_len); - if (pos == U_NOT_FOUND) U_RETURN(false); + if (idx == U_NOT_FOUND) U_RETURN(false); - pos += query_len; + idx += query_len; - UTokenizer tok(json.substr(pos)); + UTokenizer tok(json.substr(idx)); int sTok = jreadFindToken(tok); @@ -2280,7 +2628,7 @@ const char* UValue::getJReadErrorDescription() U_RETURN(descr); } -const char* UValue::getDataTypeDescription(uint32_t type) +const char* UValue::getDataTypeDescription(uint8_t type) { U_TRACE(0, "UValue::getDataTypeDescription(%u)", type) diff --git a/src/ulib/net/server/plugin/mod_proxy.cpp b/src/ulib/net/server/plugin/mod_proxy.cpp index a85ac41c..a720b0f4 100644 --- a/src/ulib/net/server/plugin/mod_proxy.cpp +++ b/src/ulib/net/server/plugin/mod_proxy.cpp @@ -208,13 +208,15 @@ int UProxyPlugIn::handlerRequest() UString body = client_http->getContent(), content_type = client_http->getResponseHeader()->getContentType(); - U_INTERNAL_ASSERT(body) + if (body && + content_type) + { + if (UHTTP::service->isReplaceResponse()) body = UHTTP::service->replaceResponse(body); - if (UHTTP::service->isReplaceResponse()) body = UHTTP::service->replaceResponse(body); + content_type.rep->_length += 2; // NB: we add "\r\n"... - content_type.rep->_length += 2; // NB: we add "\r\n"... - - UHTTP::setDynamicResponse(body, UString::getStringNull(), content_type); + UHTTP::setDynamicResponse(body, UString::getStringNull(), content_type); + } } } diff --git a/src/ulib/net/server/plugin/php/mod_php.cpp b/src/ulib/net/server/plugin/php/mod_php.cpp index f10c2609..0f9ea37d 100644 --- a/src/ulib/net/server/plugin/php/mod_php.cpp +++ b/src/ulib/net/server/plugin/php/mod_php.cpp @@ -35,6 +35,17 @@ #undef snprintf #endif +#define PHP_MAJOR_VERSION 7 +#define PHP_MINOR_VERSION 1 +#define PHP_RELEASE_VERSION 8 +#define PHP_EXTRA_VERSION "-1ubuntu1" +#define PHP_VERSION "7.1.8-1ubuntu1" +#define PHP_VERSION_ID 70108 + +#define PHP_VERSION_NUM (PHP_MAJOR_VERSION * 10000 + \ + PHP_MINOR_VERSION * 100 + \ + PHP_RELEASE_VERSION) + extern "C" { static void UPHP_set_environment(void* env, char* name, char* value) @@ -103,12 +114,21 @@ static char* read_cookies() return 0; } +#if PHP_VERSION_NUM < 70108 static void log_message(char* message) { U_TRACE(0, "PHP::log_message(%S)", message) U_SRV_LOG("%s", message); } +#else +static void log_message(char* message, int len) +{ + U_TRACE(0, "PHP::log_message(%.*S,%u)", len, message, len) + + U_SRV_LOG("%.*s", len, message); +} +#endif extern U_EXPORT bool initPHP(); U_EXPORT bool initPHP() diff --git a/src/ulib/net/server/plugin/usp/docalc1.usp b/src/ulib/net/server/plugin/usp/docalc1.usp new file mode 100644 index 00000000..6837cb18 --- /dev/null +++ b/src/ulib/net/server/plugin/usp/docalc1.usp @@ -0,0 +1,17 @@ + + diff --git a/src/ulib/serialize/flatbuffers.cpp b/src/ulib/serialize/flatbuffers.cpp new file mode 100644 index 00000000..fad947e7 --- /dev/null +++ b/src/ulib/serialize/flatbuffers.cpp @@ -0,0 +1,364 @@ +// ============================================================================ +// +// = LIBRARY +// ULib - c++ library +// +// = FILENAME +// flatbuffers.cpp +// +// = AUTHOR +// Stefano Casazza +// +// ============================================================================ + +#include + +uint8_t* UFlatBuffer::stack_str; +uint8_t* UFlatBuffer::buffer_str; +uint32_t UFlatBuffer::stack_idx; +uint32_t UFlatBuffer::stack_max; +uint32_t UFlatBuffer::buffer_max; + +UFlatBufferValue* UFlatBuffer::pkeys; +UFlatBufferValue* UFlatBuffer::pvalue; + +uint32_t UFlatBuffer::AsMapGetKeys(UVector& members) const +{ + U_TRACE(0, "UFlatBuffer::AsMapGetKeys(%p)", &members) + + UString key; + UFlatBuffer vec; + uint32_t len = members.size(); + + AsMapGetKeys(vec); + + for (uint32_t i = 0, n = vec.GetSize(); i < n; ++i) + { +# ifndef HAVE_OLD_IOSTREAM + key = vec.AsTypedOrFixedVectorGet(i); +# endif + + U_INTERNAL_DUMP("key = %V", key.rep) + + members.push(key); + } + + len = members.size() - len; + + U_RETURN(len); +} + +void UFlatBuffer::WriteAny(uint8_t byte_width) +{ + U_TRACE(0, "UFlatBuffer::WriteAny(%u)", byte_width) + + U_DUMP("pvalue->type_ = (%u,%S) pvalue->i_ = %llu", pvalue->type_, getTypeDescription(pvalue->type_), pvalue->i_) + + switch (pvalue->type_) + { + case UFlatBufferValue::TYPE_NULL: + case UFlatBufferValue::TYPE_INT: + case UFlatBufferValue::TYPE_UINT: + case UFlatBufferValue::TYPE_BOOL: WriteScalar(pvalue->u_, byte_width); break; + case UFlatBufferValue::TYPE_FLOAT: WriteDouble( pvalue->f_, byte_width); break; + + case UFlatBufferValue::TYPE_STRING: + case UFlatBufferValue::TYPE_INDIRECT_INT: + case UFlatBufferValue::TYPE_INDIRECT_UINT: + case UFlatBufferValue::TYPE_INDIRECT_FLOAT: + case UFlatBufferValue::TYPE_MAP: + case UFlatBufferValue::TYPE_VECTOR: + case UFlatBufferValue::TYPE_VECTOR_INT: + case UFlatBufferValue::TYPE_VECTOR_UINT: + case UFlatBufferValue::TYPE_VECTOR_FLOAT: + case UFlatBufferValue::TYPE_VECTOR_BOOL: + case UFlatBufferValue::TYPE_VECTOR_STRING: + case UFlatBufferValue::TYPE_VECTOR_INT2: + case UFlatBufferValue::TYPE_VECTOR_UINT2: + case UFlatBufferValue::TYPE_VECTOR_FLOAT2: + case UFlatBufferValue::TYPE_VECTOR_INT3: + case UFlatBufferValue::TYPE_VECTOR_UINT3: + case UFlatBufferValue::TYPE_VECTOR_FLOAT3: + case UFlatBufferValue::TYPE_VECTOR_INT4: + case UFlatBufferValue::TYPE_VECTOR_UINT4: + case UFlatBufferValue::TYPE_VECTOR_FLOAT4: WriteOffset(pvalue->l_, byte_width); + break; + } +} + +uint8_t* UFlatBuffer::AsMapSetIndex(const char* key, uint32_t len) +{ + U_TRACE(0, "UFlatBuffer::AsMapSetIndex(%.*S,%u)", len, key, len) + + U_INTERNAL_ASSERT(IsMap()) + + UString item; + UFlatBuffer keys; + + AsMapGetKeys(keys); + + for (uint32_t i = 0; i < keys.buffer_idx; ++i) + { +# ifndef HAVE_OLD_IOSTREAM + item = keys.AsTypedOrFixedVectorGet(i); +# endif + + U_INTERNAL_DUMP("item[%u] = %V", i, item.rep) + + if (item.equal(key, len)) return AsVectorSetIndex(i); + } + + U_INTERNAL_ASSERT(false) + + return U_NULLPTR; +} + +void UFlatBuffer::CreateVector(uint32_t start, uint32_t vec_len, uint32_t step, bool typed, bool fixed, UFlatBufferValue* pval) +{ + U_TRACE(0, "UFlatBuffer::CreateVector(%u,%u,%u,%b,%b,%p)", start, vec_len, step, typed, fixed, pval) + + U_INTERNAL_ASSERT_MAJOR(vec_len, 0) + + // Figure out smallest bit width we can store this vector with + + uint32_t i, vloc, prefix_elems = 1; + vPF nextStackPtr = (step == 1 ? nextStackPointer : next2StackPointer); + uint8_t byte_width, bit_width = UFlatBufferValue::WidthL(vec_len), elem_width, vector_type; + + if (pkeys) + { + // If this vector is part of a map, we will pre-fix an offset to the keys to this vector + + elem_width = pkeys->ElemWidth(buffer_idx, 0); + + if (bit_width < elem_width) bit_width = elem_width; + + prefix_elems += 2; + } + + // Check bit widths and types for all elements + + setStackPointer((i = start)); + + vector_type = pvalue->type_; + +loop1: + elem_width = pvalue->ElemWidth(buffer_idx, i + prefix_elems); + + U_INTERNAL_DUMP("bit_width = %u elem_width = %u", bit_width, elem_width) + + if (bit_width < elem_width) bit_width = elem_width; + +#ifdef DEBUG + if (typed) + { + U_INTERNAL_ASSERT_EQUALS(vector_type, pvalue->type_) // you are writing a typed vector with elements that are not all the same type + U_INTERNAL_ASSERT(IsTypedVectorElementType(pvalue->type_)) // your type are not one of: Int / UInt / Float / Bool / String + } +#endif + + if ((i += step) < stack_idx) + { + nextStackPtr(); + + goto loop1; + } + + byte_width = Align(bit_width); + + U_INTERNAL_DUMP("byte_width = %u vector_type = %u", byte_width, vector_type) + + // Write vector. First the keys offset/width if available, and size + + if (pkeys) + { + WriteOffset(pkeys->l_, byte_width); + + WriteScalar(1ULL << pkeys->min_bit_width_, byte_width); + } + + if (fixed == false) WriteScalar(vec_len, byte_width); + + // Then the actual data + + vloc = buffer_idx; + + setStackPointer((i = start)); + +loop2: + WriteAny(byte_width); + + if ((i += step) < stack_idx) + { + nextStackPtr(); + + goto loop2; + } + + if (typed == false) // Then the types + { + setStackPointer((i = start)); + +loop3: + WriteScalar8(pvalue->StoredPackedType(bit_width)); + + if ((i += step) < stack_idx) + { + nextStackPtr(); + + goto loop3; + } + } + + if (pval) + { + U_INTERNAL_ASSERT(typed) + U_INTERNAL_ASSERT_EQUALS(fixed, false) + U_INTERNAL_ASSERT_EQUALS(pkeys, U_NULLPTR) + U_INTERNAL_ASSERT_EQUALS(vector_type, UFlatBufferValue::TYPE_STRING) + + pval->set(vloc, ToTypedVector(vector_type, 0), bit_width); + } + else if (pkeys == U_NULLPTR) + { + stack_idx = start; // Remove temp elements + + pushOnStack(vloc, (typed ? ToTypedVector(vector_type, fixed ? vec_len : 0) : (uint8_t)UFlatBufferValue::TYPE_VECTOR), bit_width); + } + else + { + U_INTERNAL_ASSERT_EQUALS(typed, false) + U_INTERNAL_ASSERT_EQUALS(fixed, false) + + stack_idx = start-1; // Remove temp elements + + pushOnStack(vloc, UFlatBufferValue::TYPE_MAP, bit_width); + } + + U_INTERNAL_DUMP("buffer_str+vloc = %#.8S", buffer_str+vloc) +} + +void UFlatBuffer::EndMap(uint32_t start) +{ + U_TRACE(0, "UFlatBuffer::EndMap(%u)", start) + + // We should have interleaved keys and values on the stack + + U_INTERNAL_DUMP("stack_idx = %u", stack_idx) + + U_INTERNAL_ASSERT_EQUALS((stack_idx-start) & 1, false) // Make sure it is an even number + + uint32_t len = (stack_idx-start) / 2; + + U_INTERNAL_ASSERT_MAJOR(len, 0) + +#ifdef DEBUG // Make sure keys are all strings + int32_t key; + + setStackPointer((key = start)); +loop: + U_DUMP("key = %u pvalue->type_ = (%u,%S)", key, pvalue->type_, getTypeDescription(pvalue->type_)) + +// U_INTERNAL_ASSERT_EQUALS(pvalue->type_, UFlatBufferValue::TYPE_STRING) + + if ((key += 2) < (int32_t)stack_idx) + { + next2StackPointer(); + + goto loop; + } +#endif + + // First create a vector out of all keys + + uint8_t keys[20]; + + CreateVector(start, len, 2, true, false, (UFlatBufferValue*)keys); + + pkeys = (UFlatBufferValue*)keys; + + CreateVector(start+1, len, 2, false, false, U_NULLPTR); + + pkeys = U_NULLPTR; +} + +// DEBUG + +#ifdef DEBUG +const char* UFlatBuffer::getTypeDescription(uint8_t type) +{ + U_TRACE(0, "UFlatBuffer::getTypeDescription(%u)", type) + + struct type_info { + int value; // The numeric value + const char* name; // The equivalent symbolic value + }; + + static const struct type_info type_table[] = { + U_ENTRY(UFlatBufferValue::TYPE_NULL), + U_ENTRY(UFlatBufferValue::TYPE_INT), + U_ENTRY(UFlatBufferValue::TYPE_UINT), + U_ENTRY(UFlatBufferValue::TYPE_FLOAT), + U_ENTRY(UFlatBufferValue::TYPE_BOOL), + U_ENTRY(UFlatBufferValue::TYPE_STRING), + U_ENTRY(UFlatBufferValue::TYPE_INDIRECT_INT), + U_ENTRY(UFlatBufferValue::TYPE_INDIRECT_UINT), + U_ENTRY(UFlatBufferValue::TYPE_INDIRECT_FLOAT), + U_ENTRY(UFlatBufferValue::TYPE_MAP), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_INT), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_UINT), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_FLOAT), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_BOOL), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_STRING), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_INT2), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_UINT2), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_FLOAT2), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_INT3), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_UINT3), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_FLOAT3), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_INT4), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_UINT4), + U_ENTRY(UFlatBufferValue::TYPE_VECTOR_FLOAT4) + }; + + const char* descr = (type < (int)U_NUM_ELEMENTS(type_table) ? type_table[type].name : "type unknown"); + + U_RETURN(descr); +} + +const char* UFlatBuffer::dump(bool reset) const +{ +#ifdef U_STDCPP_ENABLE + *UObjectIO::os << "type_ " << type_ << '\n' + << "buffer_idx " << buffer_idx << '\n' + << "byte_width_ " << (uint32_t)byte_width_ << '\n' + << "parent_width_ " << (uint32_t)parent_width_; + + if (reset) + { + UObjectIO::output(); + + return UObjectIO::buffer_output; + } +#endif + + return U_NULLPTR; +} + +const char* UFlatBufferTypeHandler_Base::dump(bool _reset) const +{ +#ifdef U_STDCPP_ENABLE + *UObjectIO::os << "pval " << pval; + + if (_reset) + { + UObjectIO::output(); + + return UObjectIO::buffer_output; + } +#endif + + return U_NULLPTR; +} +#endif diff --git a/src/ulib/string.cpp b/src/ulib/string.cpp index 41ab6d11..28bc740a 100644 --- a/src/ulib/string.cpp +++ b/src/ulib/string.cpp @@ -1952,7 +1952,14 @@ double UString::strtod() const { UValue json; - if (json.parse(*this)) return json.getDouble(); + if (json.parse(*this)) + { + double result = (json.isDouble() ? json.getDouble() : (double)json.getPayload()); + + U_INTERNAL_DUMP("json.getDouble() = %g", json.getDouble()) + + U_RETURN(result); + } } U_RETURN(.0); diff --git a/src/ulib/utility/string_ext.cpp b/src/ulib/utility/string_ext.cpp index 74d2b5d1..7da5c819 100644 --- a/src/ulib/utility/string_ext.cpp +++ b/src/ulib/utility/string_ext.cpp @@ -313,6 +313,8 @@ UString UStringExt::substitute(const char* s, uint32_t len, UVector& ve uint32_t n = vec.size(); + U_INTERNAL_ASSERT_EQUALS(n & 1, 0) + if (n == 2) return substitute(s, len, U_STRING_TO_PARAM(vec[0]), U_STRING_TO_PARAM(vec[1])); char c; @@ -344,16 +346,13 @@ UString UStringExt::substitute(const char* s, uint32_t len, UVector& ve continue; } - if (u__islower(c)) mask_lower |= maskFirstChar[c-'a']; + if (u__isdigit(c)) bdigit = true; + else if (u__isspace(c)) bspace = true; + else if (u__islower(c)) mask_lower |= maskFirstChar[c-'a']; else if (u__isupper(c)) mask_upper |= maskFirstChar[c-'A']; - else if (u__isdigit(c)) bdigit = true; - else if (u__isspace(c)) bspace = true; } - bdollar = (dollar == n); - - U_INTERNAL_DUMP("n1 = %u n2 = %u mask_lower = %B mask_upper = %B bdigit = %b bspace = %b dollar = %u bdollar = %b", - n1, n2, mask_lower, mask_upper, bdigit, bspace, dollar, bdollar) + U_INTERNAL_DUMP("n1 = %u n2 = %u", n1, n2) if (n2 <= n1) capacity = len; else @@ -369,6 +368,11 @@ UString UStringExt::substitute(const char* s, uint32_t len, UVector& ve char* p2 = x.data(); const char* end = s + len; + bdollar = (dollar == n); + + U_INTERNAL_DUMP("mask_lower = %B mask_upper = %B bdigit = %b bspace = %b dollar = %u bdollar = %b", + mask_lower, mask_upper, bdigit, bspace, dollar, bdollar) + loop: for (p1 = s; p1 < end; ++p1) { @@ -475,6 +479,125 @@ found: U_RETURN_STRING(x); } +// The format s uses positional identifiers indicated by a dollar sign ($) and single digit +// positional ids to indicate which substitution arguments to use at that location within the format s + +UString UStringExt::substituteIds(const char* s, uint32_t len, UVector& vec) +{ + U_TRACE(1, "UStringExt::substituteIds(%.*S,%u,%p)", len, s, len, &vec) + + U_INTERNAL_ASSERT_MAJOR(len, 0) + + UString item; + uint32_t len1; + const char* p1; + bool breserve = false; + const char* end = s + len; + uint32_t i, n = vec.size(), n1 = n*2, n2 = 0, capacity, ids, old_ids = U_NOT_FOUND; + + for (i = 0; i < n; ++i) n2 += vec[i].size(); + + if (n2 <= n1) capacity = len; + else + { + capacity = n2*((len+n1)/n1); + + if (capacity > (256U * 1024U * 1024U)) capacity = (breserve = true, (256U * 1024U * 1024U)); // worst case... + } + + U_INTERNAL_DUMP("n1 = %u n2 = %u breserve = %b", n1, n2, breserve) + + UString x(capacity); + char* p2 = x.data(); + +loop: + for (p1 = s; p1 < end; ++p1) + { + U_INTERNAL_DUMP("p1 = %.10S", p1) + + if (*p1 != '$') continue; + + if (u__isdigit(p1[2]) == false) ids = (n1 = 2, p1[1] - '0'); + else + { + for (i = 3; u__isdigit(p1[i]); ++i) {} + + ids = (n1 = i, u__strtoul(p1+1, n1-1)); + } + + U_INTERNAL_DUMP("n1 = %u ids = %u old_ids = %u", n1, ids, old_ids) + + if (ids != old_ids) + { + old_ids = ids; + + n2 = (item = vec.at(ids)).size(); + + U_INTERNAL_DUMP("item(%u) = %V", n2, item.rep) + + U_INTERNAL_ASSERT_MAJOR(n2, 0) + } + + len1 = (p1-s); + + U_INTERNAL_DUMP("len1 = %u", len1) + + if (breserve) + { + uint32_t len2 = len1 + n2; + + x.rep->_length = x.distance(p2); + + if (x.space() < len2) + { + UString::_reserve(x, len2); + + p2 = x.pend(); + } + } + + if (len1) + { + U_MEMCPY(p2, s, len1); + p2 += len1; + + s = p1; + len -= len1; + } + + len -= n1; + s += n1; + + U_MEMCPY(p2, item.data(), n2); + p2 += n2; + + goto loop; + } + + x.rep->_length = x.distance(p2); + + U_INTERNAL_DUMP("len = %u", len) + + if (len) + { + if (breserve && + x.space() < len) + { + UString::_reserve(x, len); + + p2 = x.pend(); + } + + U_MEMCPY(p2, s, len); + + x.rep->_length += len; + } + + U_INTERNAL_ASSERT(x.invariant()) + + U_RETURN_STRING(x); +} + // dos2unix: '\n' <=> '\r\n' convertor UString UStringExt::dos2unix(const UString& s, bool unix2dos) diff --git a/src/ulib/utility/uhttp.cpp b/src/ulib/utility/uhttp.cpp index bdaacd83..693d65a4 100644 --- a/src/ulib/utility/uhttp.cpp +++ b/src/ulib/utility/uhttp.cpp @@ -883,7 +883,7 @@ void UHTTP::init() #endif #ifdef USE_LIBSSL -// if (UServer_Base::bssl) enable_caching_by_proxy_servers = true; + // if (UServer_Base::bssl) enable_caching_by_proxy_servers = true; #endif #if defined(USE_PAGE_SPEED) || defined(USE_LIBV8) || defined(USE_RUBY) || defined(USE_PHP) || defined(USE_PYTHON) @@ -1135,21 +1135,12 @@ void UHTTP::init() if (cache_file_store) { +# ifdef U_STDCPP_ENABLE content_cache = (UStringExt::endsWith(U_STRING_TO_PARAM(*cache_file_store), U_CONSTANT_TO_PARAM(".gz")) ? UStringExt::gunzip(UFile::contentOf(*cache_file_store)) : UFile::contentOf(*cache_file_store)); -# ifdef U_STDCPP_ENABLE - if (content_cache) - { - n += (content_cache.size() / (1024 + 512)); // NB: we assume as medium file size something like ~1.5k... - - UString2Object(U_STRING_TO_PARAM(content_cache), *cache_file); - - U_ASSERT_MAJOR(cache_file->size(), 0) - - U_SRV_LOG("Loaded cache file store: %V", cache_file_store->rep); - } + if (content_cache) n += (content_cache.size() / (1024 + 512)); // NB: we assume as medium file size something like ~1.5k... # endif } @@ -1157,6 +1148,17 @@ void UHTTP::init() if (sz > cache_file->capacity()) cache_file->allocate(u_nextPowerOfTwo(sz)); +#ifdef U_STDCPP_ENABLE + if (content_cache) + { + UString2Object(U_STRING_TO_PARAM(content_cache), *cache_file); + + U_ASSERT_MAJOR(cache_file->size(), 0) + + U_SRV_LOG("Loaded cache file store: %V", cache_file_store->rep); + } +#endif + U_INTERNAL_ASSERT_POINTER(pathname) for (uint32_t i = 0, j = vec.size(); i < j; ++i) @@ -1177,6 +1179,7 @@ void UHTTP::init() } } +#ifdef U_STDCPP_ENABLE if (cache_file_store && content_cache.empty()) { @@ -1188,6 +1191,7 @@ void UHTTP::init() if (UFile::writeTo(*cache_file_store, buffer, sz)) U_SRV_LOG("Saved (%u bytes) cache file store: %V", sz, cache_file_store->rep); } +#endif #ifdef USE_PHP U_INTERNAL_ASSERT_EQUALS(php_embed, U_NULLPTR) @@ -1226,6 +1230,7 @@ void UHTTP::init() U_INTERNAL_DUMP("htdigest = %p htpasswd = %p", htdigest, htpasswd) +#ifdef U_STDCPP_ENABLE if (htdigest || htpasswd) { @@ -1268,7 +1273,7 @@ void UHTTP::init() U_SRV_LOG("Loaded cache favicon.ico"); } -#ifdef U_HTML_PAGINATION_SUPPORT // manage css for HTML Pagination +# ifdef U_HTML_PAGINATION_SUPPORT // manage css for HTML Pagination file_data = cache_file->at(U_CONSTANT_TO_PARAM("css/pagination.min.css")); if (file_data == U_NULLPTR) @@ -1285,6 +1290,7 @@ void UHTTP::init() U_SRV_LOG("Loaded cache css store for HTML pagination"); } +# endif #endif sz = cache_file->size(); @@ -7787,6 +7793,15 @@ void UHTTP::manageRequest(service_info* GET_table, uint32_t n1, U_INTERNAL_ASSERT_EQUALS(target[0], '/') + if (target[1] == '/') + { + do { + ++target; + --target_len; + } + while (target[1] == '/'); + } + if (high == 0 || --target_len == 0) { diff --git a/src/ulib/utility/websocket.cpp b/src/ulib/utility/websocket.cpp index 3cc92505..6e8c870e 100644 --- a/src/ulib/utility/websocket.cpp +++ b/src/ulib/utility/websocket.cpp @@ -250,10 +250,12 @@ loop: payload_length = 0; payload_length_bytes_remaining = 0; - if (block_offset >= block_size) goto next; /* FALLTHRU */ + if (block_offset >= block_size) goto next; + + U_INTERNAL_DUMP("framing_state = %d", framing_state) } - U_INTERNAL_DUMP("framing_state = %d", framing_state) + /* FALLTHRU */ case DATA_FRAMING_PAYLOAD_LENGTH: // 2 { @@ -290,10 +292,12 @@ loop: framing_state = DATA_FRAMING_PAYLOAD_LENGTH_EXT; // 3 - if (block_offset >= block_size) goto next; /* FALLTHRU */ + if (block_offset >= block_size) goto next; + + U_INTERNAL_DUMP("framing_state = %d", framing_state) } - U_INTERNAL_DUMP("framing_state = %d", framing_state) + /* FALLTHRU */ case DATA_FRAMING_PAYLOAD_LENGTH_EXT: // 3 { @@ -330,10 +334,12 @@ loop: framing_state = DATA_FRAMING_MASK; // 0 } - if (block_offset >= block_size) goto next; /* FALLTHRU */ + if (block_offset >= block_size) goto next; + + U_INTERNAL_DUMP("framing_state = %d", framing_state) } - U_INTERNAL_DUMP("framing_state = %d", framing_state) + /* FALLTHRU */ case DATA_FRAMING_MASK: // 0 { @@ -357,12 +363,10 @@ loop: masking = 0; } - U_INTERNAL_DUMP("masking = %d", masking) - - /* FALLTHRU */ + U_INTERNAL_DUMP("masking = %d framing_state = %d", masking, framing_state) } - U_INTERNAL_DUMP("framing_state = %d", framing_state) + /* FALLTHRU */ case DATA_FRAMING_EXTENSION_DATA: // 4 { @@ -382,10 +386,10 @@ loop: framing_state = DATA_FRAMING_APPLICATION_DATA; // 5 } - /* FALLTHRU */ + U_INTERNAL_DUMP("framing_state = %d", framing_state) } - U_INTERNAL_DUMP("framing_state = %d", framing_state) + /* FALLTHRU */ case DATA_FRAMING_APPLICATION_DATA: // 5 { diff --git a/tests/examples/web_server.sh b/tests/examples/web_server.sh index b15a2f58..e0455b1d 100755 --- a/tests/examples/web_server.sh +++ b/tests/examples/web_server.sh @@ -79,8 +79,8 @@ userver { #DOCUMENT_ROOT docroot #PLUGIN_DIR ../../../src/ulib/net/server/plugin/.libs #ORM_DRIVER_DIR ../../../src/ulib/orm/driver/.libs - DOCUMENT_ROOT JONATHAN/docroot -#DOCUMENT_ROOT benchmark/docroot +#DOCUMENT_ROOT JONATHAN/docroot + DOCUMENT_ROOT benchmark/docroot PLUGIN_DIR ../../../../src/ulib/net/server/plugin/.libs ORM_DRIVER_DIR ../../../../src/ulib/orm/driver/.libs #DOCUMENT_ROOT . diff --git a/tests/ulib/Makefile.am b/tests/ulib/Makefile.am index b104b9e5..8c95bd42 100644 --- a/tests/ulib/Makefile.am +++ b/tests/ulib/Makefile.am @@ -4,7 +4,7 @@ AUTOMAKE_OPTIONS = ## dist-shar dist-zip EXTRA_DIST = random.cdb plugin inp ok *.test *.cpp CA private server_rpc.cfg file_config.cf file_config.gperf \ - file_config.gperf.sh file_config.key test_bison.h dialog.test redis.test elasticsearch.test twilio.test + file_config.gperf.sh file_config.key test_bison.h dialog.test redis.test elasticsearch.test twilio.test json_obj.h MAINTAINERCLEANFILES = Makefile.in @@ -18,7 +18,7 @@ PRG = test_timeval test_timer test_notifier test_string \ test_services test_base64 test_header test_entity \ test_ipaddress test_socket test_ftp test_http test_rdb_client \ test_tokenizer test_query_parser test_multipart test_command test_dialog test_json test_redis test_elasticsearch \ - test_smtp test_pop3 test_imap test_hash_map + test_smtp test_pop3 test_imap test_hash_map test_serialize ## test_twilio TST = timeval.test timer.test notifier.test string.test \ @@ -26,7 +26,7 @@ TST = timeval.test timer.test notifier.test string.test \ vector.test options.test application.test tree.test compress.test cache.test date.test \ services.test base64.test header.test entity.test \ ipaddress.test socket.test ftp.test http.test \ - tokenizer.test query_parser.test multipart.test command.test json.test hash_map.test + tokenizer.test query_parser.test multipart.test command.test json.test hash_map.test serialize.test ## pop3.test imap.test smtp.test dialog.test redis.test elasticsearch.test twilio.test if ENABLE_SHARED @@ -102,6 +102,7 @@ test_redis_SOURCES = test_redis.cpp test_mongodb_SOURCES = test_mongodb.cpp test_elasticsearch_SOURCES = test_elasticsearch.cpp test_hash_map_SOURCES = test_hash_map.cpp +test_serialize_SOURCES = test_serialize.cpp if PTHREAD PRG += test_thread @@ -242,7 +243,7 @@ TESTS = $(TST) ../reset.color ## arping.test event.test curl.test ftp.test imap.test ldap.test pop3.test sigslot.test smtp.test ssh_client.test test: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) - ../make_test.sh application.test base64.test bit_array.test cache.test cdb.test certificate.test command.test compress.test crl.test date.test des3.test dialog.test digest.test entity.test expat.test file.test file_config.test header.test http.test https.test interrupt.test json.test log.test memory_pool.test multipart.test notifier.test options.test pcre.test pkcs10.test pkcs7.test plugin.test process.test query_parser.test rdb.test rdb_client_server.test server.test server_rpc.test services.test soap_client.test soap_server.test ssl_client_server.test string.test timer.test timestamp.test timeval.test tokenizer.test tree.test unixsocket.test url.test vector.test zip.test hash_map.test ../reset.color + ../make_test.sh application.test base64.test bit_array.test cache.test cdb.test certificate.test command.test compress.test crl.test date.test des3.test dialog.test digest.test entity.test expat.test file.test file_config.test header.test http.test https.test interrupt.test json.test log.test memory_pool.test multipart.test notifier.test options.test pcre.test pkcs10.test pkcs7.test plugin.test process.test query_parser.test rdb.test rdb_client_server.test server.test server_rpc.test services.test soap_client.test soap_server.test ssl_client_server.test string.test timer.test timestamp.test timeval.test tokenizer.test tree.test unixsocket.test url.test vector.test zip.test hash_map.test serialize.test ../reset.color clean-local: -rm -rf out err core .libs *.bb* *.da *.gc* *.log test_log.log* tmp/* \ diff --git a/tests/ulib/Makefile.in b/tests/ulib/Makefile.in index 6f5a7ac9..6119800a 100644 --- a/tests/ulib/Makefile.in +++ b/tests/ulib/Makefile.in @@ -227,13 +227,13 @@ am__EXEEXT_19 = test_timeval$(EXEEXT) test_timer$(EXEEXT) \ test_dialog$(EXEEXT) test_json$(EXEEXT) test_redis$(EXEEXT) \ test_elasticsearch$(EXEEXT) test_smtp$(EXEEXT) \ test_pop3$(EXEEXT) test_imap$(EXEEXT) test_hash_map$(EXEEXT) \ - $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ - $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \ - $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \ - $(am__EXEEXT_10) $(am__EXEEXT_2) $(am__EXEEXT_3) \ - $(am__EXEEXT_11) $(am__EXEEXT_12) $(am__EXEEXT_13) \ - $(am__EXEEXT_14) $(am__EXEEXT_15) $(am__EXEEXT_16) \ - $(am__EXEEXT_17) $(am__EXEEXT_18) + test_serialize$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) \ + $(am__EXEEXT_3) $(am__EXEEXT_4) $(am__EXEEXT_5) \ + $(am__EXEEXT_6) $(am__EXEEXT_7) $(am__EXEEXT_8) \ + $(am__EXEEXT_9) $(am__EXEEXT_10) $(am__EXEEXT_2) \ + $(am__EXEEXT_3) $(am__EXEEXT_11) $(am__EXEEXT_12) \ + $(am__EXEEXT_13) $(am__EXEEXT_14) $(am__EXEEXT_15) \ + $(am__EXEEXT_16) $(am__EXEEXT_17) $(am__EXEEXT_18) am_test_application_OBJECTS = test_application.$(OBJEXT) test_application_OBJECTS = $(am_test_application_OBJECTS) test_application_LDADD = $(LDADD) @@ -462,6 +462,10 @@ am_test_redis_OBJECTS = test_redis.$(OBJEXT) test_redis_OBJECTS = $(am_test_redis_OBJECTS) test_redis_LDADD = $(LDADD) test_redis_DEPENDENCIES = $(top_builddir)/src/ulib/lib@ULIB@.la +am_test_serialize_OBJECTS = test_serialize.$(OBJEXT) +test_serialize_OBJECTS = $(am_test_serialize_OBJECTS) +test_serialize_LDADD = $(LDADD) +test_serialize_DEPENDENCIES = $(top_builddir)/src/ulib/lib@ULIB@.la am_test_server_OBJECTS = test_server.$(OBJEXT) test_server_OBJECTS = $(am_test_server_OBJECTS) test_server_LDADD = $(LDADD) @@ -625,16 +629,16 @@ SOURCES = $(product1_la_SOURCES) $(product2_la_SOURCES) \ $(test_pop3_SOURCES) $(test_process_SOURCES) \ $(test_query_parser_SOURCES) $(test_rdb_SOURCES) \ $(test_rdb_client_SOURCES) $(test_rdb_server_SOURCES) \ - $(test_redis_SOURCES) $(test_server_SOURCES) \ - $(test_services_SOURCES) $(test_smtp_SOURCES) \ - $(test_soap_client_SOURCES) $(test_soap_server_SOURCES) \ - $(test_socket_SOURCES) $(test_ssh_client_SOURCES) \ - $(test_ssl_client_SOURCES) $(test_ssl_server_SOURCES) \ - $(test_string_SOURCES) $(test_tdb_SOURCES) \ - $(test_thread_SOURCES) $(test_timer_SOURCES) \ - $(test_timestamp_SOURCES) $(test_timeval_SOURCES) \ - $(test_tokenizer_SOURCES) $(test_tree_SOURCES) \ - $(test_unixsocket_client_SOURCES) \ + $(test_redis_SOURCES) $(test_serialize_SOURCES) \ + $(test_server_SOURCES) $(test_services_SOURCES) \ + $(test_smtp_SOURCES) $(test_soap_client_SOURCES) \ + $(test_soap_server_SOURCES) $(test_socket_SOURCES) \ + $(test_ssh_client_SOURCES) $(test_ssl_client_SOURCES) \ + $(test_ssl_server_SOURCES) $(test_string_SOURCES) \ + $(test_tdb_SOURCES) $(test_thread_SOURCES) \ + $(test_timer_SOURCES) $(test_timestamp_SOURCES) \ + $(test_timeval_SOURCES) $(test_tokenizer_SOURCES) \ + $(test_tree_SOURCES) $(test_unixsocket_client_SOURCES) \ $(test_unixsocket_server_SOURCES) $(test_url_SOURCES) \ $(test_vector_SOURCES) $(test_zip_SOURCES) DIST_SOURCES = $(am__product1_la_SOURCES_DIST) \ @@ -664,9 +668,9 @@ DIST_SOURCES = $(am__product1_la_SOURCES_DIST) \ $(test_pop3_SOURCES) $(am__test_process_SOURCES_DIST) \ $(test_query_parser_SOURCES) $(test_rdb_SOURCES) \ $(test_rdb_client_SOURCES) $(test_rdb_server_SOURCES) \ - $(test_redis_SOURCES) $(test_server_SOURCES) \ - $(test_services_SOURCES) $(test_smtp_SOURCES) \ - $(am__test_soap_client_SOURCES_DIST) \ + $(test_redis_SOURCES) $(test_serialize_SOURCES) \ + $(test_server_SOURCES) $(test_services_SOURCES) \ + $(test_smtp_SOURCES) $(am__test_soap_client_SOURCES_DIST) \ $(am__test_soap_server_SOURCES_DIST) $(test_socket_SOURCES) \ $(am__test_ssh_client_SOURCES_DIST) \ $(am__test_ssl_client_SOURCES_DIST) \ @@ -1105,7 +1109,7 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = ## dist-shar dist-zip EXTRA_DIST = random.cdb plugin inp ok *.test *.cpp CA private server_rpc.cfg file_config.cf file_config.gperf \ - file_config.gperf.sh file_config.key test_bison.h dialog.test redis.test elasticsearch.test twilio.test + file_config.gperf.sh file_config.key test_bison.h dialog.test redis.test elasticsearch.test twilio.test json_obj.h MAINTAINERCLEANFILES = Makefile.in DEFAULT_INCLUDES = -I. -I$(top_builddir)/include @@ -1118,7 +1122,7 @@ PRG = test_timeval test_timer test_notifier test_string test_file \ test_http test_rdb_client test_tokenizer test_query_parser \ test_multipart test_command test_dialog test_json test_redis \ test_elasticsearch test_smtp test_pop3 test_imap test_hash_map \ - $(am__append_1) $(am__append_3) $(am__append_4) \ + test_serialize $(am__append_1) $(am__append_3) $(am__append_4) \ $(am__append_5) $(am__append_6) $(am__append_8) \ $(am__append_10) $(am__append_12) $(am__append_14) \ $(am__append_16) $(am__append_18) $(am__append_20) \ @@ -1131,12 +1135,13 @@ TST = timeval.test timer.test notifier.test string.test file.test \ cache.test date.test services.test base64.test header.test \ entity.test ipaddress.test socket.test ftp.test http.test \ tokenizer.test query_parser.test multipart.test command.test \ - json.test hash_map.test $(am__append_2) $(am__append_7) \ - $(am__append_9) $(am__append_11) $(am__append_13) \ - $(am__append_15) $(am__append_17) $(am__append_19) \ - $(am__append_21) $(am__append_23) $(am__append_25) \ - $(am__append_27) $(am__append_29) $(am__append_31) \ - $(am__append_33) $(am__append_35) $(am__append_37) + json.test hash_map.test serialize.test $(am__append_2) \ + $(am__append_7) $(am__append_9) $(am__append_11) \ + $(am__append_13) $(am__append_15) $(am__append_17) \ + $(am__append_19) $(am__append_21) $(am__append_23) \ + $(am__append_25) $(am__append_27) $(am__append_29) \ + $(am__append_31) $(am__append_33) $(am__append_35) \ + $(am__append_37) @ENABLE_PLUGINS_TRUE@@ENABLE_SHARED_TRUE@test_plugin_SOURCES = test_plugin.cpp @ENABLE_PLUGINS_TRUE@@ENABLE_SHARED_TRUE@product1_la_SOURCES = plugin/product1.cpp @ENABLE_PLUGINS_TRUE@@ENABLE_SHARED_TRUE@product1_la_LIBADD = $(LDADD) @@ -1186,6 +1191,7 @@ test_redis_SOURCES = test_redis.cpp test_mongodb_SOURCES = test_mongodb.cpp test_elasticsearch_SOURCES = test_elasticsearch.cpp test_hash_map_SOURCES = test_hash_map.cpp +test_serialize_SOURCES = test_serialize.cpp @PTHREAD_TRUE@test_thread_SOURCES = test_thread.cpp @ZIP_TRUE@test_zip_SOURCES = test_zip.cpp @LIBTDB_TRUE@test_tdb_SOURCES = test_tdb.cpp @@ -1494,6 +1500,10 @@ test_redis$(EXEEXT): $(test_redis_OBJECTS) $(test_redis_DEPENDENCIES) $(EXTRA_te @rm -f test_redis$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(test_redis_OBJECTS) $(test_redis_LDADD) $(LIBS) +test_serialize$(EXEEXT): $(test_serialize_OBJECTS) $(test_serialize_DEPENDENCIES) $(EXTRA_test_serialize_DEPENDENCIES) + @rm -f test_serialize$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(test_serialize_OBJECTS) $(test_serialize_LDADD) $(LIBS) + test_server$(EXEEXT): $(test_server_OBJECTS) $(test_server_DEPENDENCIES) $(EXTRA_test_server_DEPENDENCIES) @rm -f test_server$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(test_server_OBJECTS) $(test_server_LDADD) $(LIBS) @@ -1641,6 +1651,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_rdb_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_rdb_server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_redis.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_serialize.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_services.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_smtp.Po@am__quote@ @@ -2077,7 +2088,7 @@ uninstall-am: test: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) - ../make_test.sh application.test base64.test bit_array.test cache.test cdb.test certificate.test command.test compress.test crl.test date.test des3.test dialog.test digest.test entity.test expat.test file.test file_config.test header.test http.test https.test interrupt.test json.test log.test memory_pool.test multipart.test notifier.test options.test pcre.test pkcs10.test pkcs7.test plugin.test process.test query_parser.test rdb.test rdb_client_server.test server.test server_rpc.test services.test soap_client.test soap_server.test ssl_client_server.test string.test timer.test timestamp.test timeval.test tokenizer.test tree.test unixsocket.test url.test vector.test zip.test hash_map.test ../reset.color + ../make_test.sh application.test base64.test bit_array.test cache.test cdb.test certificate.test command.test compress.test crl.test date.test des3.test dialog.test digest.test entity.test expat.test file.test file_config.test header.test http.test https.test interrupt.test json.test log.test memory_pool.test multipart.test notifier.test options.test pcre.test pkcs10.test pkcs7.test plugin.test process.test query_parser.test rdb.test rdb_client_server.test server.test server_rpc.test services.test soap_client.test soap_server.test ssl_client_server.test string.test timer.test timestamp.test timeval.test tokenizer.test tree.test unixsocket.test url.test vector.test zip.test hash_map.test serialize.test ../reset.color clean-local: -rm -rf out err core .libs *.bb* *.da *.gc* *.log test_log.log* tmp/* \ diff --git a/tests/ulib/json_obj.h b/tests/ulib/json_obj.h new file mode 100644 index 00000000..670e40cc --- /dev/null +++ b/tests/ulib/json_obj.h @@ -0,0 +1,1548 @@ +// json_obj.h + +#include + +class Request { +public: + // Check for memory error + U_MEMORY_TEST + + // Allocator e Deallocator + U_MEMORY_ALLOCATOR + U_MEMORY_DEALLOCATOR + + UHashMap table; + UString radius, location; + UVector fbPermissions; + + Request() + { + U_TRACE_REGISTER_OBJECT(5, Request, "") + } + + ~Request() + { + U_TRACE_UNREGISTER_OBJECT(5, Request) + } + + void clear() + { + U_TRACE_NO_PARAM(5, "Request::clear()") + + + table.clear(); + radius.clear(); + location.clear(); + fbPermissions.clear(); + } + + void toJSON(UString& json) + { + U_TRACE(5, "Request::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(table, UHashMap)); + json.toJSON(U_JSON_METHOD_HANDLER(radius, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(location, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(fbPermissions, UVector)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "Request::toJSON()") + + U_JSON_TYPE_HANDLER(table, UHashMap); + U_JSON_TYPE_HANDLER(radius, UString); + U_JSON_TYPE_HANDLER(location, UString); + U_JSON_TYPE_HANDLER(fbPermissions, UVector); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "Request::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(table, UHashMap)); + json.fromJSON(U_JSON_METHOD_HANDLER(radius, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(location, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(fbPermissions, UVector)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Request::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(table, UHashMap)); + fb.toFlatBuffer(FLATBUFFER(radius, UString)); + fb.toFlatBuffer(FLATBUFFER(location, UString)); + fb.toFlatBuffer(FLATBUFFER(fbPermissions, UVector)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Request::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(table, UHashMap)); + fb.fromFlatBuffer(1, FLATBUFFER(radius, UString)); + fb.fromFlatBuffer(2, FLATBUFFER(location, UString)); + fb.fromFlatBuffer(3, FLATBUFFER(fbPermissions, UVector)); + } + +#define REQUEST_JSON \ +"{\"table\":{\"type\":\"localesData\",\"token\":\"A619828KAIJ6D3\"},\"radius\":\"near\",\"location\":\"40.7831 N,73.9712 W\",\"fbPermissions\":[\"public_profile\",\"user_friends\",\"email\"]}" + +#define REQUEST_FLATBUFFER \ +"[{\"type\":\"localesData\",\"token\":\"A619828KAIJ6D3\"},\"near\",\"40.7831 N,73.9712 W\",[\"public_profile\",\"user_friends\",\"email\"]]" + + void checkObject() + { + U_TRACE_NO_PARAM(5, "Request::checkObject()") + + U_ASSERT_EQUALS(radius, "near") + U_ASSERT_EQUALS(location, "40.7831 N,73.9712 W") + + const char* dump = UObject2String >(table); + + U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) + + U_INTERNAL_ASSERT_EQUALS(UObjectIO::buffer_output_len, U_CONSTANT_SIZE("[\ntype\tlocalesData\ntoken\tA619828KAIJ6D3\n]")) + + dump = UObject2String >(fbPermissions); + + U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) + + bool ok = U_STREQ(dump, UObjectIO::buffer_output_len, "( public_profile user_friends email )"); + + U_INTERNAL_ASSERT(ok) + } + + void setObject(const UString& json) + { + U_TRACE(5, "Request::setObject(%V)", json.rep) + + bool ok = JSON_parse(json, *this); + + U_INTERNAL_ASSERT(ok) + } + + void test(UValue& json_obj, const UString& json, UString& output) + { + U_TRACE(5, "Request::test(%p,%V,%p)", &json_obj, json.rep, &output) + + setObject(json); + + checkObject(); + + JSON_stringify(output, json_obj, *this); + + U_INTERNAL_ASSERT_EQUALS( output.size(), json.size() ) + } + + void testJSON() + { + U_TRACE_NO_PARAM(5, "Request::testJSON()") + + UValue json_obj; + UString output, reqJson = U_STRING_FROM_CONSTANT(REQUEST_JSON); + + test(json_obj, reqJson, output); + + output.clear(); + + JSON_OBJ_stringify(output, *this); + + U_INTERNAL_ASSERT_EQUALS( output.size(), reqJson.size() ) + } + + void testFlatBuffer() + { + U_TRACE_NO_PARAM(5, "Request::testFlatBuffer()") + + UFlatBuffer fb; + UValue json_obj; + + setObject(U_STRING_FROM_CONSTANT(REQUEST_JSON)); + + fb.fromObject(*this); + + json_obj.fromFlatBuffer(fb); + + U_ASSERT_EQUALS( json_obj.output(), REQUEST_FLATBUFFER ) + + clear(); + + fb.toObject(*this); + + checkObject(); + } + +#ifdef DEBUG + const char* dump(bool breset) const + { + *UObjectIO::os << "table (UHashMap " << (void*)&table << ")\n" + << "radius (UString " << (void*)&radius << ")\n" + << "location (UString " << (void*)&location << ")\n" + << "fbPermissions (UVector " << (void*)&fbPermissions << ')'; + + if (breset) + { + UObjectIO::output(); + + return UObjectIO::buffer_output; + } + + return U_NULLPTR; + } +#endif + +private: + Request& operator=(const Request&) { return *this; } +}; + +class Response { +public: + // Check for memory error + U_MEMORY_TEST + + // Allocator e Deallocator + U_MEMORY_ALLOCATOR + U_MEMORY_DEALLOCATOR + + UVector fbPermissions; + UString type, token; + UHashMap table; + + Response(): type(U_STRING_FROM_CONSTANT("startup")) + { + U_TRACE_REGISTER_OBJECT(5, Response, "") + } + + ~Response() + { + U_TRACE_UNREGISTER_OBJECT(5, Response) + } + + void clear() + { + U_TRACE_NO_PARAM(5, "Response::clear()") + + fbPermissions.clear(); + type.clear(); + token.clear(); + table.clear(); + } + + void toJSON(UString& json) + { + U_TRACE(5, "Response::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(fbPermissions, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(type, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(token, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(table, UHashMap)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "Response::toJSON()") + + U_JSON_TYPE_HANDLER(fbPermissions, UVector); + U_JSON_TYPE_HANDLER(type, UString); + U_JSON_TYPE_HANDLER(token, UString); + U_JSON_TYPE_HANDLER(table, UHashMap); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "Response::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(fbPermissions, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(type, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(token, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(table, UHashMap)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Response::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(fbPermissions, UVector)); + fb.toFlatBuffer(FLATBUFFER(type, UString)); + fb.toFlatBuffer(FLATBUFFER(token, UString)); + fb.toFlatBuffer(FLATBUFFER(table, UHashMap)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Response::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(fbPermissions, UVector)); + fb.fromFlatBuffer(1, FLATBUFFER(type, UString)); + fb.fromFlatBuffer(2, FLATBUFFER(token, UString)); + fb.fromFlatBuffer(3, FLATBUFFER(table, UHashMap)); + } + +#define RESPONSE_JSON \ +"{\"fbPermissions\":[\"public_profile\",\"user_friends\",\"email\"],\"type\":\"startup\",\"token\":\"\",\"table\":{\"type\":\"localesData\",\"token\":\"A619828KAIJ6D3\"}}" + +#define RESPONSE_FLATBUFFER \ +"[[\"public_profile\",\"user_friends\",\"email\"],\"startup\",\"\",{\"type\":\"localesData\",\"token\":\"A619828KAIJ6D3\"}]" + + void checkObject() + { + U_TRACE_NO_PARAM(5, "Response::checkObject()") + + U_ASSERT_EQUALS(token, "") + U_ASSERT_EQUALS(type, "startup") + + const char* dump = UObject2String >(fbPermissions); + + U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) + + bool ok = U_STREQ(dump, UObjectIO::buffer_output_len, "( public_profile user_friends email )"); + + U_INTERNAL_ASSERT(ok) + + dump = UObject2String >(table); + + U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) + + U_INTERNAL_ASSERT_EQUALS(UObjectIO::buffer_output_len, U_CONSTANT_SIZE("[\ntype\tlocalesData\ntoken\tA619828KAIJ6D3\n]")) + + U_INTERNAL_ASSERT(ok) + } + + void setObject(const UString& json) + { + U_TRACE(5, "Response::setObject(%V)", json.rep) + + bool ok = JSON_parse(json, *this); + + U_INTERNAL_ASSERT(ok) + } + + void test(UValue& json_obj, const UString& json, UString& output) + { + U_TRACE(5, "Response::test(%p,%V,%p)", &json_obj, json.rep, &output) + + setObject(json); + + checkObject(); + + JSON_stringify(output, json_obj, *this); + + U_INTERNAL_ASSERT_EQUALS( output.size(), json.size() ) + } + + void testJSON() + { + U_TRACE_NO_PARAM(5, "Response::testJSON()") + + UValue json_obj; + UString output, reqJson = U_STRING_FROM_CONSTANT(RESPONSE_JSON); + + test(json_obj, reqJson, output); + + output.clear(); + + JSON_OBJ_stringify(output, *this); + + U_INTERNAL_ASSERT_EQUALS( output.size(), reqJson.size() ) + } + + void testFlatBuffer() + { + U_TRACE_NO_PARAM(5, "Response::testFlatBuffer()") + + UFlatBuffer fb; + UValue json_obj; + + setObject(U_STRING_FROM_CONSTANT(RESPONSE_JSON)); + + fb.fromObject(*this); + + json_obj.fromFlatBuffer(fb); + + U_ASSERT_EQUALS( json_obj.output(), RESPONSE_FLATBUFFER ) + + clear(); + + fb.toObject(*this); + + checkObject(); + } + +#ifdef DEBUG + const char* dump(bool breset) const + { + *UObjectIO::os << "fbPermissions (UVector " << (void*)&fbPermissions << ")\n" + << "type (UString " << (void*)&type << ")\n" + << "token (UString " << (void*)&token << ")\n" + << "table (UHashMap " << (void*)&table << ')'; + + if (breset) + { + UObjectIO::output(); + + return UObjectIO::buffer_output; + } + + return U_NULLPTR; + } +#endif +}; + +class Organization { +public: + UString name, index; + + Organization() {} + Organization(const UString& _name, const UString& _index) : name(_name), index(_index) {} + + void clear() + { + U_TRACE_NO_PARAM(5, "Organization::clear()") + + name.clear(); + index.clear(); + } + + void toJSON(UString& json) + { + U_TRACE(5, "Organization::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(name, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(index, UString)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "Organization::toJSON()") + + U_JSON_TYPE_HANDLER(name, UString); + U_JSON_TYPE_HANDLER(index, UString); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "Organization::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(name, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(index, UString)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Organization::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(name, UString)); + fb.toFlatBuffer(FLATBUFFER(index, UString)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Organization::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(name, UString)); + fb.fromFlatBuffer(1, FLATBUFFER(index, UString)); + } +}; + +class Social { +public: + UString name, token; + unsigned key; + int64_t dateTime; + + Social() {} + + void clear() + { + U_TRACE_NO_PARAM(5, "Social::clear()") + + name.clear(); + token.clear(); + + key = 0; + dateTime = 0; + } + + void toJSON(UString& json) + { + U_TRACE(5, "Social::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(name, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(token, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(key, unsigned)); + json.toJSON(U_JSON_METHOD_HANDLER(dateTime, int64_t)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "Social::toJSON()") + + U_JSON_TYPE_HANDLER(name, UString); + U_JSON_TYPE_HANDLER(token, UString); + U_JSON_TYPE_HANDLER(key, unsigned); + U_JSON_TYPE_HANDLER(dateTime, int64_t); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "Social::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(name, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(token, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(key, unsigned)); + json.fromJSON(U_JSON_METHOD_HANDLER(dateTime, int64_t)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Social::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(name, UString)); + fb.toFlatBuffer(FLATBUFFER(token, UString)); + fb.toFlatBuffer(FLATBUFFER(key, unsigned)); + fb.toFlatBuffer(FLATBUFFER(dateTime, int64_t)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Social::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(name, UString)); + fb.fromFlatBuffer(1, FLATBUFFER(token, UString)); + fb.fromFlatBuffer(2, FLATBUFFER(key, unsigned)); + fb.fromFlatBuffer(3, FLATBUFFER(dateTime, int64_t)); + } +}; + +class StrangerSocial { +public: + UString name; + unsigned key; + + StrangerSocial() {} + + void clear() + { + U_TRACE_NO_PARAM(5, "StrangerSocial::clear()") + + name.clear(); + key = 0; + } + + void toJSON(UString& json) + { + U_TRACE(5, "StrangerSocial::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(name, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(key, unsigned)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "StrangerSocial::toJSON()") + + U_JSON_TYPE_HANDLER(name, UString); + U_JSON_TYPE_HANDLER(key, unsigned); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "StrangerSocial::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(name, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(key, unsigned)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "StrangerSocial::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(name, UString)); + fb.toFlatBuffer(FLATBUFFER(key, unsigned)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "StrangerSocial::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(name, UString)); + fb.fromFlatBuffer(1, FLATBUFFER(key, unsigned)); + } +}; + +class Link { +public: + UString url, imageURL; + + Link() {} + + void clear() + { + U_TRACE_NO_PARAM(5, "Link::clear()") + + url.clear(); + imageURL.clear(); + } + + void toJSON(UString& json) + { + U_TRACE(5, "Link::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(url, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(imageURL, UString)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "Link::toJSON()") + + U_JSON_TYPE_HANDLER(url, UString); + U_JSON_TYPE_HANDLER(imageURL, UString); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "Link::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(url, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(imageURL, UString)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Link::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(url, UString)); + fb.toFlatBuffer(FLATBUFFER(imageURL, UString)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Link::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(url, UString)); + fb.fromFlatBuffer(1, FLATBUFFER(imageURL, UString)); + } +}; + +class LinkPreview { +public: + + UString imageURL, URL, title, domain; + float imageWidth, imageHeight; + + LinkPreview() {} + + void toJSON(UString& json) + { + U_TRACE(5, "LinkPreview::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(imageURL, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(URL, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(title, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(domain, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(imageWidth, float)); + json.toJSON(U_JSON_METHOD_HANDLER(imageHeight, float)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "LinkPreview::toJSON()") + + U_JSON_TYPE_HANDLER(imageURL, UString); + U_JSON_TYPE_HANDLER(URL, UString); + U_JSON_TYPE_HANDLER(title, UString); + U_JSON_TYPE_HANDLER(domain, UString); + U_JSON_TYPE_HANDLER(imageWidth, float); + U_JSON_TYPE_HANDLER(imageHeight, float); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "LinkPreview::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(imageURL, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(URL, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(title, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(domain, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(imageWidth, float)); + json.fromJSON(U_JSON_METHOD_HANDLER(imageHeight, float)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "LinkPreview::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(imageURL, UString)); + fb.toFlatBuffer(FLATBUFFER(URL, UString)); + fb.toFlatBuffer(FLATBUFFER(title, UString)); + fb.toFlatBuffer(FLATBUFFER(domain, UString)); + fb.toFlatBuffer(FLATBUFFER(imageWidth, float)); + fb.toFlatBuffer(FLATBUFFER(imageHeight, float)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "LinkPreview::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(imageURL, UString)); + fb.fromFlatBuffer(1, FLATBUFFER(URL, UString)); + fb.fromFlatBuffer(2, FLATBUFFER(title, UString)); + fb.fromFlatBuffer(3, FLATBUFFER(domain, UString)); + fb.fromFlatBuffer(4, FLATBUFFER(imageWidth, float)); + fb.fromFlatBuffer(5, FLATBUFFER(imageHeight, float)); + } +}; + +class Message { +public: + UString actor, target, content; + UVector linkPreviews; + unsigned key; + UString ping; + bool becameActive; + int64_t dateTime, readTime; + + Message() {} + + void toJSON(UString& json) + { + U_TRACE(5, "Message::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(actor, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(target, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(content, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(linkPreviews, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(key, unsigned)); + json.toJSON(U_JSON_METHOD_HANDLER(ping, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(becameActive, bool)); + json.toJSON(U_JSON_METHOD_HANDLER(dateTime, int64_t)); + json.toJSON(U_JSON_METHOD_HANDLER(readTime, int64_t)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "Message::toJSON()") + + U_JSON_TYPE_HANDLER(actor, UString); + U_JSON_TYPE_HANDLER(target, UString); + U_JSON_TYPE_HANDLER(content, UString); + U_JSON_TYPE_HANDLER(linkPreviews, UVector); + U_JSON_TYPE_HANDLER(key, unsigned); + U_JSON_TYPE_HANDLER(ping, UString); + U_JSON_TYPE_HANDLER(becameActive, bool); + U_JSON_TYPE_HANDLER(dateTime, int64_t); + U_JSON_TYPE_HANDLER(readTime, int64_t); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "Message::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(actor, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(target, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(content, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(linkPreviews, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(key, unsigned)); + json.fromJSON(U_JSON_METHOD_HANDLER(ping, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(becameActive, bool)); + json.fromJSON(U_JSON_METHOD_HANDLER(dateTime, int64_t)); + json.fromJSON(U_JSON_METHOD_HANDLER(readTime, int64_t)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Message::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(actor, UString)); + fb.toFlatBuffer(FLATBUFFER(target, UString)); + fb.toFlatBuffer(FLATBUFFER(content, UString)); + fb.toFlatBuffer(FLATBUFFER(linkPreviews, UVector)); + fb.toFlatBuffer(FLATBUFFER(key, unsigned)); + fb.toFlatBuffer(FLATBUFFER(ping, UString)); + fb.toFlatBuffer(FLATBUFFER(becameActive, bool)); + fb.toFlatBuffer(FLATBUFFER(dateTime, int64_t)); + fb.toFlatBuffer(FLATBUFFER(readTime, int64_t)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Message::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(actor, UString)); + fb.fromFlatBuffer(1, FLATBUFFER(target, UString)); + fb.fromFlatBuffer(2, FLATBUFFER(content, UString)); + fb.fromFlatBuffer(3, FLATBUFFER(ping, UString)); + fb.fromFlatBuffer(4, FLATBUFFER(key, unsigned)); + fb.fromFlatBuffer(5, FLATBUFFER(linkPreviews, UVector)); + fb.fromFlatBuffer(6, FLATBUFFER(becameActive, bool)); + fb.fromFlatBuffer(7, FLATBUFFER(dateTime, int64_t)); + fb.fromFlatBuffer(8, FLATBUFFER(readTime, int64_t)); + } +}; + +class User { +public: + UString token, name, pic, applePushToken, directory; + UVector socials; + UVector links; + unsigned points, spotCount; + bool visibility; + int64_t aroundSince; + Organization work, college; + + User() {} + + void toJSON(UString& json) + { + U_TRACE(5, "User::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(token, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(name, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(pic, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(applePushToken, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(directory, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(socials, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(links, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(points, unsigned)); + json.toJSON(U_JSON_METHOD_HANDLER(spotCount, unsigned)); + json.toJSON(U_JSON_METHOD_HANDLER(visibility, bool)); + json.toJSON(U_JSON_METHOD_HANDLER(aroundSince, int64_t)); + json.toJSON(U_JSON_METHOD_HANDLER(work, Organization)); + json.toJSON(U_JSON_METHOD_HANDLER(college, Organization)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "User::toJSON()") + + U_JSON_TYPE_HANDLER(token, UString); + U_JSON_TYPE_HANDLER(name, UString); + U_JSON_TYPE_HANDLER(pic, UString); + U_JSON_TYPE_HANDLER(applePushToken, UString); + U_JSON_TYPE_HANDLER(directory, UString); + U_JSON_TYPE_HANDLER(socials, UVector); + U_JSON_TYPE_HANDLER(links, UVector); + U_JSON_TYPE_HANDLER(points, unsigned); + U_JSON_TYPE_HANDLER(spotCount, unsigned); + U_JSON_TYPE_HANDLER(visibility, bool); + U_JSON_TYPE_HANDLER(aroundSince, int64_t); + U_JSON_TYPE_HANDLER(work, Organization); + U_JSON_TYPE_HANDLER(college, Organization); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "User::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(token, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(name, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(pic, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(applePushToken, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(directory, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(socials, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(links, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(points, unsigned)); + json.fromJSON(U_JSON_METHOD_HANDLER(spotCount, unsigned)); + json.fromJSON(U_JSON_METHOD_HANDLER(visibility, bool)); + json.fromJSON(U_JSON_METHOD_HANDLER(aroundSince, int64_t)); + json.fromJSON(U_JSON_METHOD_HANDLER(work, Organization)); + json.fromJSON(U_JSON_METHOD_HANDLER(college, Organization)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "User::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(token, UString)); + fb.toFlatBuffer(FLATBUFFER(name, UString)); + fb.toFlatBuffer(FLATBUFFER(pic, UString)); + fb.toFlatBuffer(FLATBUFFER(applePushToken, UString)); + fb.toFlatBuffer(FLATBUFFER(directory, UString)); + fb.toFlatBuffer(FLATBUFFER(socials, UVector)); + fb.toFlatBuffer(FLATBUFFER(links, UVector)); + fb.toFlatBuffer(FLATBUFFER(points, unsigned)); + fb.toFlatBuffer(FLATBUFFER(spotCount, unsigned)); + fb.toFlatBuffer(FLATBUFFER(visibility, bool)); + fb.toFlatBuffer(FLATBUFFER(aroundSince, int64_t)); + fb.toFlatBuffer(FLATBUFFER(work, Organization)); + fb.toFlatBuffer(FLATBUFFER(college, Organization)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "User::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(token, UString)); + fb.fromFlatBuffer(1, FLATBUFFER(name, UString)); + fb.fromFlatBuffer(2, FLATBUFFER(pic, UString)); + fb.fromFlatBuffer(3, FLATBUFFER(applePushToken, UString)); + fb.fromFlatBuffer(4, FLATBUFFER(directory, UString)); + fb.fromFlatBuffer(5, FLATBUFFER(socials, UVector)); + fb.fromFlatBuffer(6, FLATBUFFER(links, UVector)); + fb.fromFlatBuffer(7, FLATBUFFER(points, unsigned)); + fb.fromFlatBuffer(8, FLATBUFFER(spotCount, unsigned)); + fb.fromFlatBuffer(9, FLATBUFFER(visibility, bool)); + fb.fromFlatBuffer(10, FLATBUFFER(aroundSince, int64_t)); + fb.fromFlatBuffer(11, FLATBUFFER(work, Organization)); + fb.fromFlatBuffer(12, FLATBUFFER(college, Organization)); + } +}; + +class Event { +public: + UString actor, target; + unsigned key; + int64_t dateTime; + + Event() {} + + Event(const UString& _actor, unsigned _key, int64_t _dateTime) : actor(_actor), key(_key), dateTime(_dateTime) {} + + void toJSON(UString& json) + { + U_TRACE(5, "Event::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(actor, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(target, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(key, unsigned)); + json.toJSON(U_JSON_METHOD_HANDLER(dateTime, int64_t)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "Event::toJSON()") + + U_JSON_TYPE_HANDLER(actor, UString); + U_JSON_TYPE_HANDLER(target, UString); + U_JSON_TYPE_HANDLER(key, unsigned); + U_JSON_TYPE_HANDLER(dateTime, int64_t); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "Event::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(actor, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(target, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(key, unsigned)); + json.fromJSON(U_JSON_METHOD_HANDLER(dateTime, int64_t)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Event::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(actor, UString)); + fb.toFlatBuffer(FLATBUFFER(target, UString)); + fb.toFlatBuffer(FLATBUFFER(key, unsigned)); + fb.toFlatBuffer(FLATBUFFER(dateTime, int64_t)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Event::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(actor, UString)); + fb.fromFlatBuffer(4, FLATBUFFER(target, UString)); + fb.fromFlatBuffer(8, FLATBUFFER(key, unsigned)); + fb.fromFlatBuffer(10, FLATBUFFER(dateTime, int64_t)); + } +}; + +class ResponseLogin { +public: + unsigned spotCount; + UString type, token, name, pic, directory; + UVector actives, nows, freeFileNames; + UVector links; + UVector users; + UVector messages; + UVector events; + UVector socials; + Organization work, college; + + ResponseLogin(): type(U_STRING_FROM_CONSTANT("login")) {} + + void clear() + { + U_TRACE_NO_PARAM(5, "ResponseLogin::clear()") + + spotCount = 0; + + type.clear(); + token.clear(); + name.clear(); + pic.clear(); + directory.clear(); + actives.clear(); + nows.clear(); + freeFileNames.clear(); + links.clear(); + users.clear(); + messages.clear(); + events.clear(); + socials.clear(); + work.clear(); + college.clear(); + } + + void toJSON(UString& json) + { + U_TRACE(5, "ResponseLogin::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(spotCount, unsigned)); + json.toJSON(U_JSON_METHOD_HANDLER(type, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(token, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(name, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(pic, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(directory, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(actives, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(nows, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(freeFileNames, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(links, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(users, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(messages, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(events, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(socials, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(work, Organization)); + json.toJSON(U_JSON_METHOD_HANDLER(college, Organization)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "ResponseLogin::toJSON()") + + U_JSON_TYPE_HANDLER(spotCount, unsigned); + U_JSON_TYPE_HANDLER(type, UString); + U_JSON_TYPE_HANDLER(token, UString); + U_JSON_TYPE_HANDLER(name, UString); + U_JSON_TYPE_HANDLER(pic, UString); + U_JSON_TYPE_HANDLER(directory, UString); + U_JSON_TYPE_HANDLER(actives, UVector); + U_JSON_TYPE_HANDLER(nows, UVector); + U_JSON_TYPE_HANDLER(freeFileNames, UVector); + U_JSON_TYPE_HANDLER(links, UVector); + U_JSON_TYPE_HANDLER(users, UVector); + U_JSON_TYPE_HANDLER(messages, UVector); + U_JSON_TYPE_HANDLER(events, UVector); + U_JSON_TYPE_HANDLER(socials, UVector); + U_JSON_TYPE_HANDLER(work, Organization); + U_JSON_TYPE_HANDLER(college, Organization); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "ResponseLogin::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(spotCount, unsigned)); + json.fromJSON(U_JSON_METHOD_HANDLER(type, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(token, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(name, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(pic, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(directory, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(actives, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(nows, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(freeFileNames, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(links, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(users, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(messages, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(events, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(socials, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(work, Organization)); + json.fromJSON(U_JSON_METHOD_HANDLER(college, Organization)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "ResponseLogin::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(spotCount, unsigned)); + fb.toFlatBuffer(FLATBUFFER(type, UString)); + fb.toFlatBuffer(FLATBUFFER(token, UString)); + fb.toFlatBuffer(FLATBUFFER(name, UString)); + fb.toFlatBuffer(FLATBUFFER(pic, UString)); + fb.toFlatBuffer(FLATBUFFER(directory, UString)); + fb.toFlatBuffer(FLATBUFFER(actives, UVector)); + fb.toFlatBuffer(FLATBUFFER(nows, UVector)); + fb.toFlatBuffer(FLATBUFFER(freeFileNames, UVector)); + fb.toFlatBuffer(FLATBUFFER(links, UVector)); + fb.toFlatBuffer(FLATBUFFER(users, UVector)); + fb.toFlatBuffer(FLATBUFFER(messages, UVector)); + fb.toFlatBuffer(FLATBUFFER(events, UVector)); + fb.toFlatBuffer(FLATBUFFER(socials, UVector)); + fb.toFlatBuffer(FLATBUFFER(work, Organization)); + fb.toFlatBuffer(FLATBUFFER(college, Organization)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "ResponseLogin::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(spotCount, unsigned)); + fb.fromFlatBuffer(1, FLATBUFFER(type, UString)); + fb.fromFlatBuffer(2, FLATBUFFER(token, UString)); + fb.fromFlatBuffer(3, FLATBUFFER(name, UString)); + fb.fromFlatBuffer(4, FLATBUFFER(pic, UString)); + fb.fromFlatBuffer(5, FLATBUFFER(directory, UString)); + fb.fromFlatBuffer(6, FLATBUFFER(actives, UVector)); + fb.fromFlatBuffer(7, FLATBUFFER(nows, UVector)); + fb.fromFlatBuffer(8, FLATBUFFER(freeFileNames, UVector)); + fb.fromFlatBuffer(9, FLATBUFFER(links, UVector)); + fb.fromFlatBuffer(10, FLATBUFFER(users, UVector)); + fb.fromFlatBuffer(11, FLATBUFFER(messages, UVector)); + fb.fromFlatBuffer(12, FLATBUFFER(events, UVector)); + fb.fromFlatBuffer(13, FLATBUFFER(socials, UVector)); + fb.fromFlatBuffer(14, FLATBUFFER(work, Organization)); + fb.fromFlatBuffer(15, FLATBUFFER(college, Organization)); + } + +#define RESPONSELOGIN_JSON \ +"{\"spotCount\":0,\"type\":\"login\",\"token\":\"HRq0Mgft49bF3YJaKXQCCYzZ4oRDXX5KF\",\"name\":\"victor stewart\",\"pic\":\"GRSDTbv6tqxf6P2kuVNykBsFvbZXIjsFR\",\"directory\":\"NZ45XLdN87rZJogran0y3dJl30lyw2OrQ\",\"actives\":[],\"nows\":[],\"freeFileNames\":[\"9cvxHmjzuQzzCaw2LMTvjmyMeRXM8mzXY\",\"vLivrQb9dqcRyiRa1LENgBnsSpEbFsOcN\",\"uELEMyIieNW86ruETPaISDBlnn5UOFTZr\",\"pSqtl0fITijC8BbGKvJTaSrqhgNBRDeJX\",\"sreDFtqY9a3aRU0y4PrnX4VLTJvNJUjh6\",\"1MKsg9wknND12SHLuM3NbXcO2hSxRhck8\",\"akItwhgG2JVXhUldOuSgBzrhQydIcBRRq\",\"rHc9fVz5HEN5e95834P6Ilo1ofMCjc6Vj\",\"SaMsYKXnlOWeTgm6DzcLV65R1xR0z9LSX\",\"6s982IQXEFaUbO72lDDK8wPLwrlqis9xJ\",\"5olzq3XV83bqz8ok46S2MbxvSqtjJqCYU\",\"sXTcsMH7GHVYyKNMu73UQ5Fc8weFCp4gR\",\"uHelSUm5NiHK0fP1dXMapquV3psOUd4fJ\",\"YuvfBVXQkRNQTpMLnOHKRiRM2tgQw3hv4\",\"6jQwoPPWePoHD50ZFpeuJ5OMfqYF7rog5\",\"ejh0xTPHref00GZii3YxR2Mnl1CDscS8R\",\"RDrqVKyNZkJWPhlddEOjPJYn6MHsSvyC6\",\"HxzQBW22dClawug9in1UfIEbo7IT7sb8m\",\"YRuzG4PxzMM5tlSwhZPqZ86ZBQIXlvRvQ\",\"0kxMSVcLfRjePzp14t45yTjcUlP0dlFWV\",\"RYF17ULTOh0l4NLazP9UGYewqLIWJcMk3\"],\"links\":[],\"users\":[],\"messages\":[],\"events\":[],\"socials\":[{\"name\":\"10209763296542423\",\"token\":\"EAAE2qPrDodIBAIRiZA9mP3pUpc8sQfZBtMxajCq7OL7wxHHWB8bmjs6SWj2vHJ5vC2qCL02cPkUlk2Y3WBr3kOE7WS6EL1dUwLZBnm3HZBQzTPlGogLzNZCsqAPaiZCJhLjGdVvQMNzoPYNpios6u4aFLdciq2DYV7c0806ki7ghJjOB8ApzKJof4R070wXfiePW4iZAARXe6YbW8kyrtOJFbcZBN08M4DoZD\",\"key\":3,\"dateTime\":149292654}],\"work\":{\"index\":\"\",\"name\":\"\"},\"college\":{\"index\":\"\",\"name\":\"\"}}" +#define RESPONSELOGIN_FLATBUFFER \ +"[0,\"login\",\"HRq0Mgft49bF3YJaKXQCCYzZ4oRDXX5KF\",\"victor stewart\",\"GRSDTbv6tqxf6P2kuVNykBsFvbZXIjsFR\",\"NZ45XLdN87rZJogran0y3dJl30lyw2OrQ\",[],[],[\"9cvxHmjzuQzzCaw2LMTvjmyMeRXM8mzXY\",\"vLivrQb9dqcRyiRa1LENgBnsSpEbFsOcN\",\"uELEMyIieNW86ruETPaISDBlnn5UOFTZr\",\"pSqtl0fITijC8BbGKvJTaSrqhgNBRDeJX\",\"sreDFtqY9a3aRU0y4PrnX4VLTJvNJUjh6\",\"1MKsg9wknND12SHLuM3NbXcO2hSxRhck8\",\"akItwhgG2JVXhUldOuSgBzrhQydIcBRRq\",\"rHc9fVz5HEN5e95834P6Ilo1ofMCjc6Vj\",\"SaMsYKXnlOWeTgm6DzcLV65R1xR0z9LSX\",\"6s982IQXEFaUbO72lDDK8wPLwrlqis9xJ\",\"5olzq3XV83bqz8ok46S2MbxvSqtjJqCYU\",\"sXTcsMH7GHVYyKNMu73UQ5Fc8weFCp4gR\",\"uHelSUm5NiHK0fP1dXMapquV3psOUd4fJ\",\"YuvfBVXQkRNQTpMLnOHKRiRM2tgQw3hv4\",\"6jQwoPPWePoHD50ZFpeuJ5OMfqYF7rog5\",\"ejh0xTPHref00GZii3YxR2Mnl1CDscS8R\",\"RDrqVKyNZkJWPhlddEOjPJYn6MHsSvyC6\",\"HxzQBW22dClawug9in1UfIEbo7IT7sb8m\",\"YRuzG4PxzMM5tlSwhZPqZ86ZBQIXlvRvQ\",\"0kxMSVcLfRjePzp14t45yTjcUlP0dlFWV\",\"RYF17ULTOh0l4NLazP9UGYewqLIWJcMk3\"],[],[],[],[],[[\"10209763296542423\",\"EAAE2qPrDodIBAIRiZA9mP3pUpc8sQfZBtMxajCq7OL7wxHHWB8bmjs6SWj2vHJ5vC2qCL02cPkUlk2Y3WBr3kOE7WS6EL1dUwLZBnm3HZBQzTPlGogLzNZCsqAPaiZCJhLjGdVvQMNzoPYNpios6u4aFLdciq2DYV7c0806ki7ghJjOB8ApzKJof4R070wXfiePW4iZAARXe6YbW8kyrtOJFbcZBN08M4DoZD\",3,149292654]],[\"\",\"\"],[\"\",\"\"]]" + + void checkObject() + { + U_TRACE_NO_PARAM(5, "ResponseLogin::checkObject()") + + U_ASSERT(links.empty()) + U_ASSERT(users.empty()) + U_ASSERT(messages.empty()) + U_ASSERT(events.empty()) + U_ASSERT(work.name.empty()) + U_ASSERT_EQUALS(type, "login") + U_ASSERT(college.name.empty()) + U_ASSERT_EQUALS(socials[0]->key, 3) + } + + void setObject(const UString& json) + { + U_TRACE(5, "ResponseLogin::setObject(%V)", json.rep) + + bool ok = JSON_parse(json, *this); + + U_INTERNAL_ASSERT(ok) + } + + void test(UValue& json_obj, const UString& json, UString& output) + { + U_TRACE(5, "ResponseLogin::test(%p,%V,%p)", &json_obj, json.rep, &output) + + setObject(json); + + checkObject(); + + JSON_stringify(output, json_obj, *this); + + U_INTERNAL_ASSERT_EQUALS( output.size(), json.size() ) + } + + void testJSON() + { + U_TRACE_NO_PARAM(5, "ResponseLogin::testJSON()") + + UValue json_obj; + UString output, reqJson = U_STRING_FROM_CONSTANT(RESPONSELOGIN_JSON); + + test(json_obj, reqJson, output); + + output.clear(); + + JSON_OBJ_stringify(output, *this); + + U_INTERNAL_ASSERT_EQUALS( output.size(), reqJson.size() ) + } + + void testFlatBuffer() + { + U_TRACE_NO_PARAM(5, "ResponseLogin::testFlatBuffer()") + + UFlatBuffer fb; + UValue json_obj; + + setObject(U_STRING_FROM_CONSTANT(RESPONSELOGIN_JSON)); + + fb.fromObject(*this); + + // (void) UFile::writeToTmp(U_STRING_TO_PARAM(fb.getResult()), O_RDWR | O_TRUNC, U_CONSTANT_TO_PARAM("testFlatBuffer1.%P"), 0); + + json_obj.fromFlatBuffer(fb); + + UString output = json_obj.output(); + + // (void) UFile::writeToTmp(U_STRING_TO_PARAM(output), O_RDWR | O_TRUNC, U_CONSTANT_TO_PARAM("testFlatBuffer2.%P"), 0); + + U_ASSERT_EQUALS( output, RESPONSELOGIN_FLATBUFFER ) + + clear(); + + fb.toObject(*this); + + checkObject(); + } +}; + +class ResponseSearch { +public: + + UString type; + unsigned key; + UVector organizations; + + ResponseSearch() : type(U_STRING_FROM_CONSTANT("search")) {} + + void clear() + { + U_TRACE_NO_PARAM(5, "ResponseSearch::clear()") + + key = 0; + + type.clear(); + organizations.clear(); + } + + void toJSON(UString& json) + { + U_TRACE(5, "ResponseSearch::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(type, UString)); + json.toJSON(U_JSON_METHOD_HANDLER(key, unsigned)); + json.toJSON(U_JSON_METHOD_HANDLER(organizations, UVector)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "ResponseSearch::toJSON()") + + U_JSON_TYPE_HANDLER(type, UString); + U_JSON_TYPE_HANDLER(key, unsigned); + U_JSON_TYPE_HANDLER(organizations, UVector); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "ResponseSearch::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(type, UString)); + json.fromJSON(U_JSON_METHOD_HANDLER(key, unsigned)); + json.fromJSON(U_JSON_METHOD_HANDLER(organizations, UVector)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "ResponseSearch::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(type, UString)); + fb.toFlatBuffer(FLATBUFFER(key, unsigned)); + fb.toFlatBuffer(FLATBUFFER(organizations, UVector)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "ResponseSearch::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(type, UString)); + fb.fromFlatBuffer(1, FLATBUFFER(key, unsigned)); + fb.fromFlatBuffer(2, FLATBUFFER(organizations, UVector)); + } + +#define RESPONSESEARCH_JSON \ +"{\"type\":\"localesData\",\"key\":0,\"organizations\":[{\"name\":\"Temple University\",\"index\":\"S119\"},{\"name\":\"Tennessee State University\",\"index\":\"S266\"},{\"name\":\"Tennessee Technological University\",\"index\":\"S224\"},{\"name\":\"Texas A&M University--College Station\",\"index\":\"S75\"},{\"name\":\"Texas A&M University--Commerce\",\"index\":\"S267\"}]}" + +#define RESPONSESEARCH_FLATBUFFER \ +"[\"localesData\",0,[[\"Temple University\",\"S119\"],[\"Tennessee State University\",\"S266\"],[\"Tennessee Technological University\",\"S224\"],[\"Texas A&M University--College Station\",\"S75\"],[\"Texas A&M University--Commerce\",\"S267\"]]]" + + void checkObject() + { + U_TRACE_NO_PARAM(5, "ResponseSearch::checkObject()") + + U_INTERNAL_ASSERT_EQUALS(key, 0) + U_ASSERT_EQUALS(type, "localesData") + U_ASSERT_EQUALS(organizations[0]->name, "Temple University") + U_ASSERT_EQUALS(organizations[0]->index, "S119") + U_ASSERT_EQUALS(organizations[4]->name, "Texas A&M University--Commerce") + U_ASSERT_EQUALS(organizations[4]->index, "S267") + } + + void setObject(const UString& json) + { + U_TRACE(5, "ResponseSearch::setObject(%V)", json.rep) + + bool ok = JSON_parse(json, *this); + + U_INTERNAL_ASSERT(ok) + } + + void test(UValue& json_obj, const UString& json, UString& output) + { + U_TRACE(5, "ResponseSearch::test(%p,%V,%p)", &json_obj, json.rep, &output) + + setObject(json); + + checkObject(); + + JSON_stringify(output, json_obj, *this); + + U_INTERNAL_ASSERT_EQUALS( output.size(), json.size() ) + } + + void testJSON() + { + U_TRACE_NO_PARAM(5, "ResponseSearch::testJSON()") + + UValue json_obj; + UString output, reqJson = U_STRING_FROM_CONSTANT(RESPONSESEARCH_JSON); + + test(json_obj, reqJson, output); + + output.clear(); + + JSON_OBJ_stringify(output, *this); + + U_INTERNAL_ASSERT_EQUALS( output.size(), reqJson.size() ) + } + + void testFlatBuffer() + { + U_TRACE_NO_PARAM(5, "ResponseSearch::testFlatBuffer()") + + UFlatBuffer fb; + UValue json_obj; + + setObject(U_STRING_FROM_CONSTANT(RESPONSESEARCH_JSON)); + + fb.fromObject(*this); + + json_obj.fromFlatBuffer(fb); + + UString output = json_obj.output(); + + // (void) UFile::writeToTmp(U_STRING_TO_PARAM(output), O_RDWR | O_TRUNC, U_CONSTANT_TO_PARAM("testFlatBuffer.%P"), 0); + + U_ASSERT_EQUALS( output, RESPONSESEARCH_FLATBUFFER ) + + clear(); + + fb.toObject(*this); + + checkObject(); + } +}; + +class Multiple { +public: + // Check for memory error + U_MEMORY_TEST + + // Allocator e Deallocator + U_MEMORY_ALLOCATOR + U_MEMORY_DEALLOCATOR + + UVector organizations; + UVector vrequests; + Request request; + Response response; + Response* presponse; + + Multiple() + { + U_NEW(Response, presponse, Response); + } + + ~Multiple() + { + delete presponse; + } + + void clear() + { + U_TRACE_NO_PARAM(5, "Multiple::clear()") + + organizations.clear(); + vrequests.clear(); + request.clear(); + response.clear(); + + delete presponse; + U_NEW(Response, presponse, Response); + } + + void toJSON(UString& json) + { + U_TRACE(5, "Multiple::toJSON(%V)", json.rep) + + json.toJSON(U_JSON_METHOD_HANDLER(organizations, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(vrequests, UVector)); + json.toJSON(U_JSON_METHOD_HANDLER(request, Request)); + json.toJSON(U_JSON_METHOD_HANDLER(response, Response)); + json.toJSON(U_JSON_METHOD_HANDLER(presponse, Response)); + } + + void toJSON() + { + U_TRACE_NO_PARAM(5, "Multiple::toJSON()") + + U_JSON_TYPE_HANDLER(organizations, UVector); + U_JSON_TYPE_HANDLER(vrequests, UVector); + U_JSON_TYPE_HANDLER(request, Request); + U_JSON_TYPE_HANDLER(response, Response); + U_JSON_TYPE_HANDLER(presponse, Response); + } + + void fromJSON(UValue& json) + { + U_TRACE(5, "Multiple::fromJSON(%p)", &json) + + json.fromJSON(U_JSON_METHOD_HANDLER(organizations, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(vrequests, UVector)); + json.fromJSON(U_JSON_METHOD_HANDLER(request, Request)); + json.fromJSON(U_JSON_METHOD_HANDLER(response, Response)); + json.fromJSON(U_JSON_METHOD_HANDLER(presponse, Response)); + } + + void toFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Multiple::toFlatBuffer(%p)", &fb) + + fb.toFlatBuffer(FLATBUFFER(organizations, UVector)); + fb.toFlatBuffer(FLATBUFFER(vrequests, UVector)); + fb.toFlatBuffer(FLATBUFFER(request, Request)); + fb.toFlatBuffer(FLATBUFFER(response, Response)); + fb.toFlatBuffer(FLATBUFFER(presponse, Response)); + } + + void fromFlatBuffer(UFlatBuffer& fb) + { + U_TRACE(5, "Multiple::fromFlatBuffer(%p)", &fb) + + fb.fromFlatBuffer(0, FLATBUFFER(organizations, UVector)); + fb.fromFlatBuffer(1, FLATBUFFER(vrequests, UVector)); + fb.fromFlatBuffer(2, FLATBUFFER(request, Request)); + fb.fromFlatBuffer(3, FLATBUFFER(response, Response)); + fb.fromFlatBuffer(4, FLATBUFFER(presponse, Response)); + } + +#define MULTIPLE_JSON \ +"{" \ +"\"organizations\":[{\"name\":\"Temple University\",\"index\":\"S119\"},{\"name\":\"Tennessee State University\",\"index\":\"S266\"},{\"name\":\"Tennessee Technological University\",\"index\":\"S224\"},{\"name\":\"Texas A&M University--College Station\",\"index\":\"S75\"},{\"name\":\"Texas A&M University--Commerce\",\"index\":\"S267\"}]," \ +"\"vrequests\":[]," \ +"\"request\":{\"table\":{\"type\":\"localesData\",\"token\":\"A619828KAIJ6D3\"},\"radius\":\"near\",\"location\":\"40.7831 N, 73.9712 W\",\"fbPermissions\":[\"public_profile\",\"user_friends\",\"email\"]}," \ +"\"response\":{\"fbPermissions\":[\"public_profile\",\"user_friends\",\"email\"],\"type\":\"startup\",\"token\":\"\",\"table\":{\"type\":\"localesData\",\"token\":\"A619828KAIJ6D3\"}}," \ +"\"presponse\":{\"fbPermissions\":[],\"type\":\"\",\"token\":\"\",\"table\":{}}" \ +"}" + +#define MULTIPLE_FLATBUFFER \ +"[" \ +"[[\"Temple University\",\"S119\"],[\"Tennessee State University\",\"S266\"],[\"Tennessee Technological University\",\"S224\"],[\"Texas A&M University--College Station\",\"S75\"],[\"Texas A&M University--Commerce\",\"S267\"]]," \ +"[]," \ +"[{\"type\":\"localesData\",\"token\":\"A619828KAIJ6D3\"},\"near\",\"40.7831 N, 73.9712 W\",[\"public_profile\",\"user_friends\",\"email\"]]," \ +"[[\"public_profile\",\"user_friends\",\"email\"],\"startup\",\"\",{\"type\":\"localesData\",\"token\":\"A619828KAIJ6D3\"}]," \ +"[[],\"\",\"\",{}]" \ +"]" + + void checkObject() + { + U_TRACE_NO_PARAM(5, "Multiple::checkObject()") + + U_ASSERT_EQUALS(request.radius, "near") + U_ASSERT_EQUALS(request.location, "40.7831 N, 73.9712 W") + + const char* dump = UObject2String >(request.table); + + U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) + + U_INTERNAL_ASSERT_EQUALS(UObjectIO::buffer_output_len, U_CONSTANT_SIZE("[\ntype\tlocalesData\ntoken\tA619828KAIJ6D3\n]")) + + dump = UObject2String >(request.fbPermissions); + + U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) + + bool ok = U_STREQ(dump, UObjectIO::buffer_output_len, "( public_profile user_friends email )"); + + U_INTERNAL_ASSERT(ok) + + U_ASSERT_EQUALS(response.token, "") + U_ASSERT_EQUALS(response.type, "startup") + + dump = UObject2String >(response.fbPermissions); + + U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) + + ok = U_STREQ(dump, UObjectIO::buffer_output_len, "( public_profile user_friends email )"); + + U_INTERNAL_ASSERT(ok) + + dump = UObject2String >(response.table); + + U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) + + U_INTERNAL_ASSERT_EQUALS(UObjectIO::buffer_output_len, U_CONSTANT_SIZE("[\ntype\tlocalesData\ntoken\tA619828KAIJ6D3\n]")) + } + + void setObject(const UString& json) + { + U_TRACE(5, "Multiple::setObject(%V)", json.rep) + + bool ok = JSON_parse(json, *this); + + U_INTERNAL_ASSERT(ok) + } + + void test(UValue& json_obj, const UString& json, UString& output) + { + U_TRACE(5, "Multiple::test(%p,%V,%p)", &json_obj, json.rep, &output) + + setObject(json); + + checkObject(); + + JSON_stringify(output, json_obj, *this); + + U_INTERNAL_ASSERT_EQUALS( output.size(), json.size() ) + } + + void testJSON() + { + U_TRACE_NO_PARAM(5, "Multiple::testJSON()") + + UValue json_obj; + UString output, reqJson = U_STRING_FROM_CONSTANT(MULTIPLE_JSON); + + test(json_obj, reqJson, output); + + output.clear(); + + JSON_OBJ_stringify(output, *this); + + U_INTERNAL_ASSERT_EQUALS( output.size(), reqJson.size() ) + } + + void testFlatBuffer() + { + U_TRACE_NO_PARAM(5, "Multiple::testFlatBuffer()") + + UFlatBuffer fb; + UValue json_obj; + + setObject(U_STRING_FROM_CONSTANT(MULTIPLE_JSON)); + + fb.fromObject(*this); + + json_obj.fromFlatBuffer(fb); + + UString output = json_obj.output(); + + // (void) UFile::writeToTmp(U_STRING_TO_PARAM(output), O_RDWR | O_TRUNC, U_CONSTANT_TO_PARAM("testFlatBuffer.%P"), 0); + + U_ASSERT_EQUALS( output, MULTIPLE_FLATBUFFER ) + + clear(); + + fb.toObject(*this); + + checkObject(); + } +}; diff --git a/tests/ulib/ok/serialize.ok b/tests/ulib/ok/serialize.ok new file mode 100644 index 00000000..e69de29b diff --git a/tests/ulib/serialize.test b/tests/ulib/serialize.test new file mode 100755 index 00000000..4ea5ce9e --- /dev/null +++ b/tests/ulib/serialize.test @@ -0,0 +1,19 @@ +#!/bin/sh + +. ../.function + +## serialize.test -- Test serialize feature + +start_msg serialize + +#UTRACE="0 30M -1" +#UOBJDUMP="0 100k 10" +#USIMERR="error.sim" + export UTRACE UOBJDUMP USIMERR + +#STRACE=$LTRUSS +#VALGRIND=valgrind +start_prg serialize isNumeric()) - cout << "We found " << total->getUInt() << std::endl; + cout << "We found " << total->getNumber() << std::endl; } } @@ -133,7 +133,7 @@ int U_EXPORT main(int argc, char* argv[], char* env[]) U_INTERNAL_ASSERT_POINTER(total) U_ASSERT(total->isNumeric()) - cout << "We found " << total->getUInt() << std::endl; + cout << "We found " << total->getNumber() << std::endl; } } diff --git a/tests/ulib/test_json.cpp b/tests/ulib/test_json.cpp index 2c9e3977..1b12024f 100644 --- a/tests/ulib/test_json.cpp +++ b/tests/ulib/test_json.cpp @@ -1,773 +1,9 @@ // test_json.cpp #include -#include #include -class Request { -public: - // Check for memory error - U_MEMORY_TEST - - // Allocator e Deallocator - U_MEMORY_ALLOCATOR - U_MEMORY_DEALLOCATOR - - UHashMap table; - UString radius, location; - UVector fbPermissions; - - Request() - { - U_TRACE_REGISTER_OBJECT(5, Request, "") - } - - ~Request() - { - U_TRACE_UNREGISTER_OBJECT(5, Request) - } - - void clear() - { - U_TRACE_NO_PARAM(5, "Request::clear()") - - - table.clear(); - radius.clear(); - location.clear(); - fbPermissions.clear(); - } - - void toJSON(UString& json) - { - U_TRACE(5, "Request::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(table, UHashMap)); - json.toJSON(U_JSON_METHOD_HANDLER(radius, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(location, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(fbPermissions, UVector)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "Request::toJSON()") - - U_JSON_TYPE_HANDLER(table, UHashMap); - U_JSON_TYPE_HANDLER(radius, UString); - U_JSON_TYPE_HANDLER(location, UString); - U_JSON_TYPE_HANDLER(fbPermissions, UVector); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "Request::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(table, UHashMap)); - json.fromJSON(U_JSON_METHOD_HANDLER(radius, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(location, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(fbPermissions, UVector)); - } - -#ifdef DEBUG - const char* dump(bool breset) const - { - *UObjectIO::os << "table (UHashMap " << (void*)&table << ")\n" - << "radius (UString " << (void*)&radius << ")\n" - << "location (UString " << (void*)&location << ")\n" - << "fbPermissions (UVector " << (void*)&fbPermissions << ')'; - - if (breset) - { - UObjectIO::output(); - - return UObjectIO::buffer_output; - } - - return U_NULLPTR; - } -#endif - -private: - Request& operator=(const Request&) { return *this; } -}; - -class Response { -public: - // Check for memory error - U_MEMORY_TEST - - // Allocator e Deallocator - U_MEMORY_ALLOCATOR - U_MEMORY_DEALLOCATOR - - UVector fbPermissions; - UString type, token; - UHashMap table; - - Response(): type(U_STRING_FROM_CONSTANT("startup")) - { - U_TRACE_REGISTER_OBJECT(5, Response, "") - } - - ~Response() - { - U_TRACE_UNREGISTER_OBJECT(5, Response) - } - - void clear() - { - U_TRACE_NO_PARAM(5, "Response::clear()") - - fbPermissions.clear(); - type.clear(); - token.clear(); - table.clear(); - } - - void toJSON(UString& json) - { - U_TRACE(5, "Response::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(fbPermissions, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(type, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(token, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(table, UHashMap)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "Response::toJSON()") - - U_JSON_TYPE_HANDLER(fbPermissions, UVector); - U_JSON_TYPE_HANDLER(type, UString); - U_JSON_TYPE_HANDLER(token, UString); - U_JSON_TYPE_HANDLER(table, UHashMap); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "Response::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(fbPermissions, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(type, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(token, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(table, UHashMap)); - } - -#ifdef DEBUG - const char* dump(bool breset) const - { - *UObjectIO::os << "fbPermissions (UVector " << (void*)&fbPermissions << ")\n" - << "type (UString " << (void*)&type << ")\n" - << "token (UString " << (void*)&token << ")\n" - << "table (UHashMap " << (void*)&table << ')'; - - if (breset) - { - UObjectIO::output(); - - return UObjectIO::buffer_output; - } - - return U_NULLPTR; - } -#endif -}; - -class Organization { -public: - UString name, index; - - Organization() {} - Organization(const UString& _name, const UString& _index) : name(_name), index(_index) {} - - void clear() - { - U_TRACE_NO_PARAM(5, "Organization::clear()") - - name.clear(); - index.clear(); - } - - void toJSON(UString& json) - { - U_TRACE(5, "Organization::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(name, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(index, UString)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "Organization::toJSON()") - - U_JSON_TYPE_HANDLER(name, UString); - U_JSON_TYPE_HANDLER(index, UString); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "Organization::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(name, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(index, UString)); - } -}; - -class Social { -public: - UString name, token; - unsigned key; - int64_t dateTime; - - Social() {} - - void clear() - { - U_TRACE_NO_PARAM(5, "Social::clear()") - - name.clear(); - token.clear(); - - key = 0; - dateTime = 0; - } - - void toJSON(UString& json) - { - U_TRACE(5, "Social::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(name, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(token, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(key, unsigned)); - json.toJSON(U_JSON_METHOD_HANDLER(dateTime, int64_t)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "Social::toJSON()") - - U_JSON_TYPE_HANDLER(name, UString); - U_JSON_TYPE_HANDLER(token, UString); - U_JSON_TYPE_HANDLER(key, unsigned); - U_JSON_TYPE_HANDLER(dateTime, int64_t); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "Social::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(name, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(token, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(key, unsigned)); - json.fromJSON(U_JSON_METHOD_HANDLER(dateTime, int64_t)); - } -}; - -class StrangerSocial { -public: - UString name; - unsigned key; - - StrangerSocial() {} - - void clear() - { - U_TRACE_NO_PARAM(5, "StrangerSocial::clear()") - - name.clear(); - key = 0; - } - - void toJSON(UString& json) - { - U_TRACE(5, "StrangerSocial::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(name, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(key, unsigned)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "StrangerSocial::toJSON()") - - U_JSON_TYPE_HANDLER(name, UString); - U_JSON_TYPE_HANDLER(key, unsigned); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "StrangerSocial::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(name, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(key, unsigned)); - } -}; - -class Link { -public: - - UString url, imageURL; - - Link() {} - - void clear() - { - U_TRACE_NO_PARAM(5, "Link::clear()") - - url.clear(); - imageURL.clear(); - } - - void toJSON(UString& json) - { - U_TRACE(5, "Link::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(url, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(imageURL, UString)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "Link::toJSON()") - - U_JSON_TYPE_HANDLER(url, UString); - U_JSON_TYPE_HANDLER(imageURL, UString); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "Link::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(url, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(imageURL, UString)); - } -}; - -class LinkPreview { -public: - - UString imageURL, URL, title, domain; - float imageWidth, imageHeight; - - LinkPreview() {} - - void toJSON(UString& json) - { - U_TRACE(5, "LinkPreview::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(imageURL, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(URL, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(title, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(domain, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(imageWidth, float)); - json.toJSON(U_JSON_METHOD_HANDLER(imageHeight, float)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "LinkPreview::toJSON()") - - U_JSON_TYPE_HANDLER(imageURL, UString); - U_JSON_TYPE_HANDLER(URL, UString); - U_JSON_TYPE_HANDLER(title, UString); - U_JSON_TYPE_HANDLER(domain, UString); - U_JSON_TYPE_HANDLER(imageWidth, float); - U_JSON_TYPE_HANDLER(imageHeight, float); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "LinkPreview::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(imageURL, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(URL, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(title, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(domain, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(imageWidth, float)); - json.fromJSON(U_JSON_METHOD_HANDLER(imageHeight, float)); - } -}; - -class Message { -public: - UString actor, target, content; - UVector linkPreviews; - unsigned key; - UString ping; - bool becameActive; - int64_t dateTime, readTime; - - Message() {} - - void toJSON(UString& json) - { - U_TRACE(5, "Message::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(actor, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(target, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(content, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(linkPreviews, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(key, unsigned)); - json.toJSON(U_JSON_METHOD_HANDLER(ping, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(becameActive, bool)); - json.toJSON(U_JSON_METHOD_HANDLER(dateTime, int64_t)); - json.toJSON(U_JSON_METHOD_HANDLER(readTime, int64_t)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "Message::toJSON()") - - U_JSON_TYPE_HANDLER(actor, UString); - U_JSON_TYPE_HANDLER(target, UString); - U_JSON_TYPE_HANDLER(content, UString); - U_JSON_TYPE_HANDLER(linkPreviews, UVector); - U_JSON_TYPE_HANDLER(key, unsigned); - U_JSON_TYPE_HANDLER(ping, UString); - U_JSON_TYPE_HANDLER(becameActive, bool); - U_JSON_TYPE_HANDLER(dateTime, int64_t); - U_JSON_TYPE_HANDLER(readTime, int64_t); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "Message::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(actor, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(target, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(content, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(linkPreviews, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(key, unsigned)); - json.fromJSON(U_JSON_METHOD_HANDLER(ping, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(becameActive, bool)); - json.fromJSON(U_JSON_METHOD_HANDLER(dateTime, int64_t)); - json.fromJSON(U_JSON_METHOD_HANDLER(readTime, int64_t)); - } -}; - -class User { -public: - UString token, name, pic, applePushToken, directory; - UVector socials; - UVector links; - unsigned points, spotCount; - bool visibility; - int64_t aroundSince; - Organization work, college; - - User() {} - - void toJSON(UString& json) - { - U_TRACE(5, "User::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(token, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(name, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(pic, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(applePushToken, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(directory, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(socials, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(links, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(points, unsigned)); - json.toJSON(U_JSON_METHOD_HANDLER(spotCount, unsigned)); - json.toJSON(U_JSON_METHOD_HANDLER(visibility, bool)); - json.toJSON(U_JSON_METHOD_HANDLER(aroundSince, int64_t)); - json.toJSON(U_JSON_METHOD_HANDLER(work, Organization)); - json.toJSON(U_JSON_METHOD_HANDLER(college, Organization)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "User::toJSON()") - - U_JSON_TYPE_HANDLER(token, UString); - U_JSON_TYPE_HANDLER(name, UString); - U_JSON_TYPE_HANDLER(pic, UString); - U_JSON_TYPE_HANDLER(applePushToken, UString); - U_JSON_TYPE_HANDLER(directory, UString); - U_JSON_TYPE_HANDLER(socials, UVector); - U_JSON_TYPE_HANDLER(links, UVector); - U_JSON_TYPE_HANDLER(points, unsigned); - U_JSON_TYPE_HANDLER(spotCount, unsigned); - U_JSON_TYPE_HANDLER(visibility, bool); - U_JSON_TYPE_HANDLER(aroundSince, int64_t); - U_JSON_TYPE_HANDLER(work, Organization); - U_JSON_TYPE_HANDLER(college, Organization); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "User::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(token, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(name, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(pic, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(applePushToken, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(directory, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(socials, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(links, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(points, unsigned)); - json.fromJSON(U_JSON_METHOD_HANDLER(spotCount, unsigned)); - json.fromJSON(U_JSON_METHOD_HANDLER(visibility, bool)); - json.fromJSON(U_JSON_METHOD_HANDLER(aroundSince, int64_t)); - json.fromJSON(U_JSON_METHOD_HANDLER(work, Organization)); - json.fromJSON(U_JSON_METHOD_HANDLER(college, Organization)); - } -}; - -class Event { -public: - UString actor, target; - unsigned key; - int64_t dateTime; - - Event() {} - - Event(const UString& _actor, unsigned _key, int64_t _dateTime) : actor(_actor), key(_key), dateTime(_dateTime) {} - - void toJSON(UString& json) - { - U_TRACE(5, "Event::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(actor, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(target, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(key, unsigned)); - json.toJSON(U_JSON_METHOD_HANDLER(dateTime, int64_t)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "Event::toJSON()") - - U_JSON_TYPE_HANDLER(actor, UString); - U_JSON_TYPE_HANDLER(target, UString); - U_JSON_TYPE_HANDLER(key, unsigned); - U_JSON_TYPE_HANDLER(dateTime, int64_t); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "Event::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(actor, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(target, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(key, unsigned)); - json.fromJSON(U_JSON_METHOD_HANDLER(dateTime, int64_t)); - } -}; - -class ResponseLogin { -public: - unsigned spotCount; - UString type, token, name, pic, directory; - UVector actives, nows, freeFileNames; - UVector links; - UVector users; - UVector messages; - UVector events; - UVector socials; - Organization work, college; - - ResponseLogin(): type(U_STRING_FROM_CONSTANT("login")) {} - - void clear() - { - U_TRACE_NO_PARAM(5, "ResponseLogin::clear()") - - spotCount = 0; - - type.clear(); - token.clear(); - name.clear(); - pic.clear(); - directory.clear(); - actives.clear(); - nows.clear(); - freeFileNames.clear(); - links.clear(); - users.clear(); - messages.clear(); - events.clear(); - socials.clear(); - work.clear(); - college.clear(); - } - - void toJSON(UString& json) - { - U_TRACE(5, "ResponseLogin::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(spotCount, unsigned)); - json.toJSON(U_JSON_METHOD_HANDLER(type, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(token, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(name, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(pic, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(directory, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(actives, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(nows, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(freeFileNames, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(links, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(users, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(messages, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(events, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(socials, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(work, Organization)); - json.toJSON(U_JSON_METHOD_HANDLER(college, Organization)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "ResponseLogin::toJSON()") - - U_JSON_TYPE_HANDLER(spotCount, unsigned); - U_JSON_TYPE_HANDLER(type, UString); - U_JSON_TYPE_HANDLER(token, UString); - U_JSON_TYPE_HANDLER(name, UString); - U_JSON_TYPE_HANDLER(pic, UString); - U_JSON_TYPE_HANDLER(directory, UString); - U_JSON_TYPE_HANDLER(actives, UVector); - U_JSON_TYPE_HANDLER(nows, UVector); - U_JSON_TYPE_HANDLER(freeFileNames, UVector); - U_JSON_TYPE_HANDLER(links, UVector); - U_JSON_TYPE_HANDLER(users, UVector); - U_JSON_TYPE_HANDLER(messages, UVector); - U_JSON_TYPE_HANDLER(events, UVector); - U_JSON_TYPE_HANDLER(socials, UVector); - U_JSON_TYPE_HANDLER(work, Organization); - U_JSON_TYPE_HANDLER(college, Organization); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "ResponseLogin::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(spotCount, unsigned)); - json.fromJSON(U_JSON_METHOD_HANDLER(type, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(token, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(name, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(pic, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(directory, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(actives, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(nows, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(freeFileNames, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(links, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(users, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(messages, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(events, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(socials, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(work, Organization)); - json.fromJSON(U_JSON_METHOD_HANDLER(college, Organization)); - } -}; - -class ResponseSearch { -public: - - UString type; - unsigned key; - UVector organizations; - - ResponseSearch() : type(U_STRING_FROM_CONSTANT("search")) {} - - void toJSON(UString& json) - { - U_TRACE(5, "ResponseSearch::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(type, UString)); - json.toJSON(U_JSON_METHOD_HANDLER(key, unsigned)); - json.toJSON(U_JSON_METHOD_HANDLER(organizations, UVector)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "ResponseSearch::toJSON()") - - U_JSON_TYPE_HANDLER(type, UString); - U_JSON_TYPE_HANDLER(key, unsigned); - U_JSON_TYPE_HANDLER(organizations, UVector); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "ResponseSearch::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(type, UString)); - json.fromJSON(U_JSON_METHOD_HANDLER(key, unsigned)); - json.fromJSON(U_JSON_METHOD_HANDLER(organizations, UVector)); - } -}; - -class Multiple { -public: - // Check for memory error - U_MEMORY_TEST - - // Allocator e Deallocator - U_MEMORY_ALLOCATOR - U_MEMORY_DEALLOCATOR - - UVector organizations; - UVector vrequests; - Request request; - Response response; - Response* presponse; - - Multiple() - { - U_NEW(Response, presponse, Response); - } - - ~Multiple() - { - delete presponse; - } - - void clear() - { - U_TRACE_NO_PARAM(5, "Multiple::clear()") - - organizations.clear(); - vrequests.clear(); - request.clear(); - response.clear(); - - presponse = U_NULLPTR; - } - - void toJSON(UString& json) - { - U_TRACE(5, "Multiple::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(organizations, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(vrequests, UVector)); - json.toJSON(U_JSON_METHOD_HANDLER(request, Request)); - json.toJSON(U_JSON_METHOD_HANDLER(response, Response)); - json.toJSON(U_JSON_METHOD_HANDLER(presponse, Response)); - } - - void toJSON() - { - U_TRACE_NO_PARAM(5, "Multiple::toJSON()") - - U_JSON_TYPE_HANDLER(organizations, UVector); - U_JSON_TYPE_HANDLER(vrequests, UVector); - U_JSON_TYPE_HANDLER(request, Request); - U_JSON_TYPE_HANDLER(response, Response); - U_JSON_TYPE_HANDLER(presponse, Response); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "Multiple::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(organizations, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(vrequests, UVector)); - json.fromJSON(U_JSON_METHOD_HANDLER(request, Request)); - json.fromJSON(U_JSON_METHOD_HANDLER(response, Response)); - json.fromJSON(U_JSON_METHOD_HANDLER(presponse, Response)); - } -}; +#include "json_obj.h" static void testMap() { @@ -873,222 +109,6 @@ static void testVector() U_ASSERT_EQUALS( result, vecJson ) } -static void testRequest() -{ - U_TRACE_NO_PARAM(5, "testRequest()") - - UValue json_obj; - Request request; - const char* dump; - UString result, reqJson = U_STRING_FROM_CONSTANT("{\"table\":{\"type\":\"localesData\",\"token\":\"A619828KAIJ6D3\"},\"radius\":\"near\",\"location\":\"40.7831 N, 73.9712 W\",\"fbPermissions\":[\"public_profile\",\"user_friends\",\"email\"]}"); - - bool ok = JSON_parse(reqJson, request); - - U_INTERNAL_ASSERT(ok) - - U_INTERNAL_ASSERT_EQUALS(request.radius, "near") - U_INTERNAL_ASSERT_EQUALS(request.location, "40.7831 N, 73.9712 W") - - dump = UObject2String >(request.table); - - U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) - - U_INTERNAL_ASSERT_EQUALS(UObjectIO::buffer_output_len, U_CONSTANT_SIZE("[\ntype\tlocalesData\ntoken\tA619828KAIJ6D3\n]")) - - dump = UObject2String >(request.fbPermissions); - - U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) - - ok = U_STREQ(dump, UObjectIO::buffer_output_len, "( public_profile user_friends email )"); - - U_INTERNAL_ASSERT(ok) - - JSON_stringify(result, json_obj, request); - - U_INTERNAL_ASSERT_EQUALS( result.size(), reqJson.size() ) - - result.clear(); - - JSON_OBJ_stringify(result, request); - - U_INTERNAL_ASSERT_EQUALS( result.size(), reqJson.size() ) -} - -static void testResponse() -{ - U_TRACE_NO_PARAM(5, "testResponse()") - - UValue json_obj; - const char* dump; - Response response; - UString result, reqJson = U_STRING_FROM_CONSTANT("{\"fbPermissions\":[\"public_profile\",\"user_friends\",\"email\"],\"type\":\"startup\",\"token\":\"\",\"table\":{\"type\":\"localesData\",\"token\":\"A619828KAIJ6D3\"}}"); - - bool ok = JSON_parse(reqJson, response); - - U_INTERNAL_ASSERT(ok) - - U_INTERNAL_ASSERT_EQUALS(response.token, "") - U_INTERNAL_ASSERT_EQUALS(response.type, "startup") - - dump = UObject2String >(response.fbPermissions); - - U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) - - ok = U_STREQ(dump, UObjectIO::buffer_output_len, "( public_profile user_friends email )"); - - U_INTERNAL_ASSERT(ok) - - dump = UObject2String >(response.table); - - U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) - - U_INTERNAL_ASSERT_EQUALS(UObjectIO::buffer_output_len, U_CONSTANT_SIZE("[\ntype\tlocalesData\ntoken\tA619828KAIJ6D3\n]")) - - U_INTERNAL_ASSERT(ok) - - JSON_stringify(result, json_obj, response); - - U_INTERNAL_ASSERT_EQUALS( result.size(), reqJson.size() ) - - result.clear(); - - JSON_OBJ_stringify(result, response); - - U_INTERNAL_ASSERT_EQUALS( result.size(), reqJson.size() ) -} - -static void testResponseLogin() -{ - U_TRACE_NO_PARAM(5, "testResponseLogin()") - - UValue json_obj; - ResponseLogin response; - UString result, reqJson = U_STRING_FROM_CONSTANT("{\"spotCount\":0,\"type\":\"login\",\"token\":\"HRq0Mgft49bF3YJaKXQCCYzZ4oRDXX5KF\",\"name\":\"victor stewart\",\"pic\":\"GRSDTbv6tqxf6P2kuVNykBsFvbZXIjsFR\",\"directory\":\"NZ45XLdN87rZJogran0y3dJl30lyw2OrQ\",\"actives\":[],\"nows\":[],\"freeFileNames\":[\"9cvxHmjzuQzzCaw2LMTvjmyMeRXM8mzXY\",\"vLivrQb9dqcRyiRa1LENgBnsSpEbFsOcN\",\"uELEMyIieNW86ruETPaISDBlnn5UOFTZr\",\"pSqtl0fITijC8BbGKvJTaSrqhgNBRDeJX\",\"sreDFtqY9a3aRU0y4PrnX4VLTJvNJUjh6\",\"1MKsg9wknND12SHLuM3NbXcO2hSxRhck8\",\"akItwhgG2JVXhUldOuSgBzrhQydIcBRRq\",\"rHc9fVz5HEN5e95834P6Ilo1ofMCjc6Vj\",\"SaMsYKXnlOWeTgm6DzcLV65R1xR0z9LSX\",\"6s982IQXEFaUbO72lDDK8wPLwrlqis9xJ\",\"5olzq3XV83bqz8ok46S2MbxvSqtjJqCYU\",\"sXTcsMH7GHVYyKNMu73UQ5Fc8weFCp4gR\",\"uHelSUm5NiHK0fP1dXMapquV3psOUd4fJ\",\"YuvfBVXQkRNQTpMLnOHKRiRM2tgQw3hv4\",\"6jQwoPPWePoHD50ZFpeuJ5OMfqYF7rog5\",\"ejh0xTPHref00GZii3YxR2Mnl1CDscS8R\",\"RDrqVKyNZkJWPhlddEOjPJYn6MHsSvyC6\",\"HxzQBW22dClawug9in1UfIEbo7IT7sb8m\",\"YRuzG4PxzMM5tlSwhZPqZ86ZBQIXlvRvQ\",\"0kxMSVcLfRjePzp14t45yTjcUlP0dlFWV\",\"RYF17ULTOh0l4NLazP9UGYewqLIWJcMk3\"],\"links\":[],\"users\":[],\"messages\":[],\"events\":[],\"socials\":[{\"name\":\"10209763296542423\",\"token\":\"EAAE2qPrDodIBAIRiZA9mP3pUpc8sQfZBtMxajCq7OL7wxHHWB8bmjs6SWj2vHJ5vC2qCL02cPkUlk2Y3WBr3kOE7WS6EL1dUwLZBnm3HZBQzTPlGogLzNZCsqAPaiZCJhLjGdVvQMNzoPYNpios6u4aFLdciq2DYV7c0806ki7ghJjOB8ApzKJof4R070wXfiePW4iZAARXe6YbW8kyrtOJFbcZBN08M4DoZD\",\"key\":3,\"dateTime\":149292654}],\"work\":{\"index\":\"\",\"name\":\"\"},\"college\":{\"index\":\"\",\"name\":\"\"}}"); - - bool ok = JSON_parse(reqJson, response); - - U_INTERNAL_ASSERT(ok) - - U_ASSERT(response.links.empty()) - U_ASSERT(response.users.empty()) - U_ASSERT(response.messages.empty()) - U_ASSERT(response.events.empty()) - U_ASSERT(response.work.name.empty()) - U_ASSERT_EQUALS(response.type, "login") - U_ASSERT(response.college.name.empty()) - U_ASSERT_EQUALS(response.socials[0]->key, 3) - - JSON_stringify(result, json_obj, response); - -// (void) UFile::writeToTmp(U_STRING_TO_PARAM(result), O_RDWR | O_TRUNC, U_CONSTANT_TO_PARAM("test_json.%P"), 0); - - U_ASSERT_EQUALS( result.size(), reqJson.size() ) - - result.clear(); - - JSON_OBJ_stringify(result, response); - - U_ASSERT_EQUALS( result.size(), reqJson.size() ) -} - -static void testResponseSearch() -{ - U_TRACE_NO_PARAM(5, "testResponseSearch()") - - UValue json_obj; - ResponseSearch response; - UString result, reqJson = U_STRING_FROM_CONSTANT("{\"type\":\"localesData\",\"key\":0,\"organizations\":[{\"name\":\"Temple University\",\"index\":\"S119\"},{\"name\":\"Tennessee State University\",\"index\":\"S266\"},{\"name\":\"Tennessee Technological University\",\"index\":\"S224\"},{\"name\":\"Texas A&M University--College Station\",\"index\":\"S75\"},{\"name\":\"Texas A&M University--Commerce\",\"index\":\"S267\"}]}"); - - bool ok = JSON_parse(reqJson, response); - - U_INTERNAL_ASSERT(ok) - - U_INTERNAL_ASSERT_EQUALS(response.key, 0) - U_ASSERT_EQUALS(response.type, "localesData") - U_ASSERT_EQUALS(response.organizations[0]->name, "Temple University") - U_ASSERT_EQUALS(response.organizations[0]->index, "S119") - U_ASSERT_EQUALS(response.organizations[4]->name, "Texas A&M University--Commerce") - U_ASSERT_EQUALS(response.organizations[4]->index, "S267") - - JSON_stringify(result, json_obj, response); - -// (void) UFile::writeToTmp(U_STRING_TO_PARAM(result), O_RDWR | O_TRUNC, U_CONSTANT_TO_PARAM("test_json.%P"), 0); - - U_ASSERT_EQUALS( result, reqJson ) - - result.clear(); - - JSON_OBJ_stringify(result, response); - - U_ASSERT_EQUALS( result, reqJson ) -} - -static void testMultiple() -{ - U_TRACE_NO_PARAM(5, "testMultiple()") - - UValue json_obj; - const char* dump; - Multiple multiple; - UString result, reqJson = U_STRING_FROM_CONSTANT("{" - "\"organizations\":[{\"name\":\"Temple University\",\"index\":\"S119\"},{\"name\":\"Tennessee State University\",\"index\":\"S266\"},{\"name\":\"Tennessee Technological University\",\"index\":\"S224\"},{\"name\":\"Texas A&M University--College Station\",\"index\":\"S75\"},{\"name\":\"Texas A&M University--Commerce\",\"index\":\"S267\"}]," - "\"vrequests\":[]," - "\"request\":{\"table\":{\"type\":\"localesData\",\"token\":\"A619828KAIJ6D3\"},\"radius\":\"near\",\"location\":\"40.7831 N, 73.9712 W\",\"fbPermissions\":[\"public_profile\",\"user_friends\",\"email\"]}," - "\"response\":{\"fbPermissions\":[\"public_profile\",\"user_friends\",\"email\"],\"type\":\"startup\",\"token\":\"\",\"table\":{\"type\":\"localesData\",\"token\":\"A619828KAIJ6D3\"}}," - "\"presponse\":{\"fbPermissions\":[],\"type\":\"\",\"token\":\"\",\"table\":{}}" - "}"); - - bool ok = JSON_parse(reqJson, multiple); - - U_INTERNAL_ASSERT(ok) - - U_INTERNAL_ASSERT_EQUALS(multiple.request.radius, "near") - U_INTERNAL_ASSERT_EQUALS(multiple.request.location, "40.7831 N, 73.9712 W") - - dump = UObject2String >(multiple.request.table); - - U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) - - U_INTERNAL_ASSERT_EQUALS(UObjectIO::buffer_output_len, U_CONSTANT_SIZE("[\ntype\tlocalesData\ntoken\tA619828KAIJ6D3\n]")) - - dump = UObject2String >(multiple.request.fbPermissions); - - U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) - - ok = U_STREQ(dump, UObjectIO::buffer_output_len, "( public_profile user_friends email )"); - - U_INTERNAL_ASSERT(ok) - - U_INTERNAL_ASSERT_EQUALS(multiple.response.token, "") - U_INTERNAL_ASSERT_EQUALS(multiple.response.type, "startup") - - dump = UObject2String >(multiple.response.fbPermissions); - - U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) - - ok = U_STREQ(dump, UObjectIO::buffer_output_len, "( public_profile user_friends email )"); - - U_INTERNAL_ASSERT(ok) - - dump = UObject2String >(multiple.response.table); - - U_INTERNAL_DUMP("dump(%u) = %.*S)", UObjectIO::buffer_output_len, UObjectIO::buffer_output_len, dump) - - U_INTERNAL_ASSERT_EQUALS(UObjectIO::buffer_output_len, U_CONSTANT_SIZE("[\ntype\tlocalesData\ntoken\tA619828KAIJ6D3\n]")) - - JSON_stringify(result, json_obj, multiple); - -// (void) UFile::writeToTmp(U_STRING_TO_PARAM(result), O_RDWR | O_TRUNC, U_CONSTANT_TO_PARAM("test_json.%P"), 0); - - U_INTERNAL_ASSERT_EQUALS( result.size(), reqJson.size() ) - - result.clear(); - - JSON_OBJ_stringify(result, multiple); - - U_INTERNAL_ASSERT_EQUALS( result.size(), reqJson.size() ) -} - // Do a query and print the results static void testQuery(const UString& json, const char* cquery, const UString& expected) @@ -1134,12 +154,12 @@ U_EXPORT main (int argc, char* argv[], char* env[]) testMap(); testVector(); - testRequest(); - testResponse(); - testResponseLogin(); - testResponseSearch(); - testMultiple(); + Request().testJSON(); + Response().testJSON(); + ResponseLogin().testJSON(); + ResponseSearch().testJSON(); + Multiple().testJSON(); content = UFile::contentOf(U_STRING_FROM_CONSTANT("inp/json/prova.json")); diff --git a/tests/ulib/test_memory_pool.cpp b/tests/ulib/test_memory_pool.cpp index 0473e554..61db829f 100644 --- a/tests/ulib/test_memory_pool.cpp +++ b/tests/ulib/test_memory_pool.cpp @@ -38,7 +38,6 @@ static void print_size() U_PRINT_SIZEOF(UFtpClient); // U_PRINT_SIZEOF(UFuncSlot); U_PRINT_SIZEOF(UHashMap); - U_PRINT_SIZEOF(UHashMapNode); U_PRINT_SIZEOF(UHttpClient); U_PRINT_SIZEOF(UIPAddress); #ifdef HAVE_LDAP diff --git a/tests/ulib/test_serialize.cpp b/tests/ulib/test_serialize.cpp new file mode 100644 index 00000000..38e5feab --- /dev/null +++ b/tests/ulib/test_serialize.cpp @@ -0,0 +1,848 @@ +// test_serialize.cpp + +#include +#include + +#include "json_obj.h" + +static void check(UFlatBuffer& fb, const UString& to_parse, const UString& expect) +{ + U_TRACE(5, "check(%p,%V,%V)", &fb, to_parse.rep, expect.rep) + + UString result = fb.getResult(); + + U_ASSERT_EQUALS(result, expect) + + UValue json; + bool ok = json.parse(to_parse); + + U_INTERNAL_ASSERT(ok) + + result = json.toFlatBuffer(); + + U_ASSERT_EQUALS(result, expect) + + json.clear(); + json.fromFlatBuffer(fb); + + result = json.output(); + + U_ASSERT_EQUALS(result, to_parse) +} + +int U_EXPORT main(int argc, char* argv[], char* env[]) +{ + U_ULIB_INIT(argv); + + U_TRACE(5, "main(%d)", argc) + + uint64_t i, size; + uint8_t stack[1024]; + UFlatBuffer fb, vec, vec0, map, map0; + uint64_t vec1[] = {1, 2, 3, 7}; + bool vec2[] = {true, false, true}; + double vec3[] = {1.0, 0.2, 0.5, 5.6}; + + UFlatBuffer::setStack(stack, sizeof(stack)); + + Request().testFlatBuffer(); + Response().testFlatBuffer(); + ResponseLogin().testFlatBuffer(); + ResponseSearch().testFlatBuffer(); + + // Write the json equivalent of: "" + + size = fb.encode([&]() { fb.String(U_CONSTANT_TO_PARAM("")); }); + + fb.setRoot(); + + U_ASSERT(fb.AsString().isNull()) + + check(fb, U_STRING_FROM_CONSTANT("\"\""), U_HEXDUMP("00001401")); + + // Write the json equivalent of: [] + + fb.StartBuild(); + fb.AddVectorEmpty(); + (void) fb.EndBuild(); + + fb.setRoot(); + fb.AsTypedVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 0) + + check(fb, U_STRING_FROM_CONSTANT("[]"), U_HEXDUMP("00003801")); + + // Write the json equivalent of: {} + + fb.StartBuild(); + fb.AddMapEmpty(); + (void) fb.EndBuild(); + + fb.setRoot(); + fb.AsMap(map); + + U_ASSERT_EQUALS(map.GetSize(), 0) + + check(fb, U_STRING_FROM_CONSTANT("{}"), U_HEXDUMP("00010100002401")); + + // Write the json equivalent of: 140737488355327 + + size = fb.encode([&]() { fb.UInt(U_VALUE_PAYLOAD_MASK); }); + + fb.setRoot(); + i = fb.AsUInt64(); + + U_INTERNAL_ASSERT_EQUALS(i, U_VALUE_PAYLOAD_MASK) + + check(fb, U_STRING_FROM_CONSTANT("140737488355327"), U_HEXDUMP("ffffffffff7f00000b08")); + + // Write the json equivalent of: "Fred" + + size = fb.encode([&]() { fb.String(U_CONSTANT_TO_PARAM("Fred")); }); + + fb.setRoot(); + UString x = fb.AsString(); + + U_ASSERT_EQUALS(x, "Fred") + + check(fb, U_STRING_FROM_CONSTANT("\"Fred\""), U_STRING_FROM_CONSTANT("\004Fred\004\024\001")); + + // Write the json equivalent of: [ 1, 2 ] + + size = fb.encodeVector([&]() { + fb.UInt(1); + fb.UInt(2); + }, true, true); + + fb.setRoot(); + fb.AsFixedTypedVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 2) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(0), 1) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(1), 2) + U_ASSERT(vec.AsTypedOrFixedVectorIsEqual(vec1, 2)) + + check(fb, U_STRING_FROM_CONSTANT("[1,2]"), U_STRING_FROM_CONSTANT("\001\002\002D\001")); + + // Write the json equivalent of: [ true, false, true ] + + size = fb.encodeVector([&]() { + fb.Bool(true); + fb.Bool(false); + fb.Bool(true); + }, true); + + fb.setRoot(); + fb.AsTypedVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 3) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(0), true) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(1), false) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(2), true) + U_ASSERT(vec.AsTypedOrFixedVectorIsEqual(vec2, 3)) + + check(fb, U_STRING_FROM_CONSTANT("[true,false,true]"), U_STRING_FROM_CONSTANT("\003\001\000\001\0038\001")); + + // Write the json equivalent of: [ 1, 2, 3 ] + + size = fb.encodeVector([&]() { + fb.UInt(1); + fb.UInt(2); + fb.UInt(3); + }, true, true); + + fb.setRoot(); + fb.AsFixedTypedVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 3) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(0), 1) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(1), 2) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(2), 3) + U_ASSERT(vec.AsTypedOrFixedVectorIsEqual(vec1, 3)) + + check(fb, U_STRING_FROM_CONSTANT("[1,2,3]"), U_STRING_FROM_CONSTANT("\001\002\003\003P\001")); + + // Write the json equivalent of: [ 1.0, 0.2, 0.5, 5.6 ] + + size = fb.encodeVector([&]() { + fb.Double(1.0); + fb.Double(0.2); + fb.Double(0.5); + fb.Double(5.6); + }, true, true); + + fb.setRoot(); + fb.AsFixedTypedVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 4) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(0), 1.0) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(1), 0.2) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(2), 0.5) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(3), 5.6) + U_ASSERT(vec.AsTypedOrFixedVectorIsEqual(vec3, 4)) + + check(fb, U_STRING_FROM_CONSTANT("[1.0,0.2,0.5,5.6]"), U_HEXDUMP("000000000000f03f9a9999999999c93f000000000000e03f6666666666661640206301")); + + // Write the json equivalent of: [ "uno", "due", "tre" ] + + size = fb.encodeVector([&]() { + fb.String(U_CONSTANT_TO_PARAM("uno")); + fb.String(U_CONSTANT_TO_PARAM("due")); + fb.String(U_CONSTANT_TO_PARAM("tre")); + }, true); + + fb.setRoot(); + fb.AsTypedVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 3) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(0), "uno") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(1), "due") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(2), "tre") + + check(fb, U_STRING_FROM_CONSTANT("[\"uno\",\"due\",\"tre\"]"), U_STRING_FROM_CONSTANT("\003uno\003due\003tre\003\f\t\006\003<\001")); + + size = fb.encodeVector([&]() { + fb.String(U_CONSTANT_TO_PARAM("9cvxHmjzuQzzCaw2LMTvjmyMeRXM8mzXY")); + fb.String(U_CONSTANT_TO_PARAM("vLivrQb9dqcRyiRa1LENgBnsSpEbFsOcN")); + fb.String(U_CONSTANT_TO_PARAM("uELEMyIieNW86ruETPaISDBlnn5UOFTZr")); + fb.String(U_CONSTANT_TO_PARAM("pSqtl0fITijC8BbGKvJTaSrqhgNBRDeJX")); + fb.String(U_CONSTANT_TO_PARAM("sreDFtqY9a3aRU0y4PrnX4VLTJvNJUjh6")); + fb.String(U_CONSTANT_TO_PARAM("1MKsg9wknND12SHLuM3NbXcO2hSxRhck8")); + fb.String(U_CONSTANT_TO_PARAM("akItwhgG2JVXhUldOuSgBzrhQydIcBRRq")); + fb.String(U_CONSTANT_TO_PARAM("RYF17ULTOh0l4NLazP9UGYewqLIWJcMk3")); + }, true); + + fb.setRoot(); + fb.AsTypedVector(vec); + +// (void) UFile::writeToTmp(U_STRING_TO_PARAM(fb.getResult()), O_RDWR | O_TRUNC, U_CONSTANT_TO_PARAM("test_serialize.%P"), 0); + + U_ASSERT_EQUALS(vec.GetSize(), 8) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(0), "9cvxHmjzuQzzCaw2LMTvjmyMeRXM8mzXY") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(1), "vLivrQb9dqcRyiRa1LENgBnsSpEbFsOcN") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(2), "uELEMyIieNW86ruETPaISDBlnn5UOFTZr") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(3), "pSqtl0fITijC8BbGKvJTaSrqhgNBRDeJX") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(4), "sreDFtqY9a3aRU0y4PrnX4VLTJvNJUjh6") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(5), "1MKsg9wknND12SHLuM3NbXcO2hSxRhck8") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(7), "RYF17ULTOh0l4NLazP9UGYewqLIWJcMk3") + + // Write the json equivalent of: [ 100, true, 4.0, "Fred" ] + + size = fb.encodeVector([&]() { + fb.UInt(100); + fb.Bool(true); + fb.Double(4.0); + fb.String(U_CONSTANT_TO_PARAM("Fred")); + }); + + fb.setRoot(); + fb.AsVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 4) + U_ASSERT_EQUALS(vec.AsVectorGet(0), 100) + U_ASSERT_EQUALS(vec.AsVectorGet(1), true) + U_ASSERT_EQUALS(vec.AsVectorGet(2), 4.0) + U_ASSERT_EQUALS(vec.AsVectorGet(3), "Fred") + + check(fb, U_STRING_FROM_CONSTANT("[100,true,4.0,\"Fred\"]"), U_HEXDUMP("044672656404000000640000000100000000008040140000000a120e14142a01")); + + // Write the json equivalent of: [ [ 1, 2 ], [ 1, 2 ], [ 1, 2 ] ] + + size = fb.encodeVector([&]() { + fb.Vector([&]() { + fb.UInt(1); + fb.UInt(2); + }, true, true); + fb.Vector([&]() { + fb.UInt(1); + fb.UInt(2); + }, true, true); + fb.Vector([&]() { + fb.UInt(1); + fb.UInt(2); + }, true, true); + }); + + fb.setRoot(); + fb.AsVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 3) + + vec.AsVectorGetFixedTypedVector(0, vec0); + + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(0), 1) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), 2) + U_ASSERT(vec0.AsTypedOrFixedVectorIsEqual(vec1, 2)) + + vec.AsVectorGetFixedTypedVector(1, vec0); + + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(0), 1) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), 2) + U_ASSERT(vec0.AsTypedOrFixedVectorIsEqual(vec1, 2)) + + vec.AsVectorGetFixedTypedVector(2, vec0); + + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(0), 1) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), 2) + U_ASSERT(vec0.AsTypedOrFixedVectorIsEqual(vec1, 2)) + + check(fb, U_STRING_FROM_CONSTANT("[[1,2],[1,2],[1,2]]"), U_HEXDUMP("01020102010203070605444444062801")); + + // Write the json equivalent of: [ 1.0, [ ], [ 1, 2 ], [ ], [ 1, 2 ], [ ] ] + + size = fb.encodeVector([&]() { + fb.Double(1.0); + fb.AddVectorEmpty(); + fb.Vector([&]() { + fb.UInt(1); + fb.UInt(2); + }, true, true); + fb.AddVectorEmpty(); + fb.Vector([&]() { + fb.UInt(1); + fb.UInt(2); + }, true, true); + fb.AddVectorEmpty(); + }); + + fb.setRoot(); + fb.AsVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 6) + U_ASSERT_EQUALS(vec.AsVectorGet(0), 1.0) + + vec.AsVectorGetFixedTypedVector(2, vec0); + + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(0), 1) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), 2) + U_ASSERT(vec0.AsTypedOrFixedVectorIsEqual(vec1, 2)) + + vec.AsVectorGetFixedTypedVector(4, vec0); + + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(0), 1) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), 2) + U_ASSERT(vec0.AsTypedOrFixedVectorIsEqual(vec1, 2)) + + check(fb, U_STRING_FROM_CONSTANT("[1.0,[],[1,2],[],[1,2],[]]"), U_HEXDUMP("00010200010200060000000000803f0e000000120000001300000017000000180000000e38443844381e2a01")); + + // Write the json equivalent of: [ 1.0, [], [], [ "uno", "due", "tre" ] ] + + size = fb.encodeVector([&]() { + fb.Double(1.0); + fb.AddVectorEmpty(); + fb.AddVectorEmpty(); + fb.Vector([&]() { + fb.String(U_CONSTANT_TO_PARAM("uno")); + fb.String(U_CONSTANT_TO_PARAM("due")); + fb.String(U_CONSTANT_TO_PARAM("tre")); + }, true); + }); + + fb.setRoot(); + fb.AsVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 4) + U_ASSERT_EQUALS(vec.AsVectorGet(0), 1.0) + vec.AsVectorGetTypedVector(1, vec0); + U_ASSERT_EQUALS(vec0.GetSize(), 0) + vec.AsVectorGetTypedVector(2, vec0); + U_ASSERT_EQUALS(vec0.GetSize(), 0) + + vec.AsVectorGetTypedVector(3, vec0); + + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(0), "uno") + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), "due") + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(2), "tre") + + check(fb, U_STRING_FROM_CONSTANT("[1.0,[],[],[\"uno\",\"due\",\"tre\"]]"), U_HEXDUMP("000003756e6f0364756503747265030c0906040000000000803f190000001c000000130000000e38383c142a01")); + + // Write the json equivalent of: [ 1.0, {}, [ 1, 2 ], {}, [ 1, 2 ], {} ] + + size = fb.encodeVector([&]() { + fb.Double(1.0); + fb.AddMapEmpty(); + fb.Vector([&]() { + fb.UInt(1); + fb.UInt(2); + }, true, true); + fb.AddMapEmpty(); + fb.Vector([&]() { + fb.UInt(1); + fb.UInt(2); + }, true, true); + fb.AddMapEmpty(); + }); + + fb.setRoot(); + fb.AsVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 6) + U_ASSERT_EQUALS(vec.AsVectorGet(0), 1.0) + + vec.AsVectorGetFixedTypedVector(2, vec0); + + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(0), 1) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), 2) + U_ASSERT(vec0.AsTypedOrFixedVectorIsEqual(vec1, 2)) + + vec.AsVectorGetFixedTypedVector(4, vec0); + + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(0), 1) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), 2) + U_ASSERT(vec0.AsTypedOrFixedVectorIsEqual(vec1, 2)) + + check(fb, U_STRING_FROM_CONSTANT("[1.0,{},[1,2],{},[1,2],{}]"), U_HEXDUMP("00010100010200010100010200010100060000000000803f1400000018000000160000001a000000180000000e24442444241e2a01")); + + // Write the json equivalent of: { foo: 13, bar: 14 } + + size = fb.encodeMap([&]() { + fb.UInt(U_CONSTANT_TO_PARAM("foo"), 13); + fb.UInt(U_CONSTANT_TO_PARAM("bar"), 14); + }); + + fb.setRoot(); + fb.AsMap(map); + + U_ASSERT_EQUALS(map.GetSize(), 2) + + map.AsMapGetKeys(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 2) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(0), "foo") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(1), "bar") + + UVector v; + + U_ASSERT_EQUALS(map.AsMapGetKeys(v), 2) + U_ASSERT_EQUALS(v[0], "foo") + U_ASSERT_EQUALS(v[1], "bar") + + map.AsMapGetValues(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 2) + U_ASSERT_EQUALS(vec.AsVectorGet(0), 13) + U_ASSERT_EQUALS(vec.AsVectorGet(1), 14) + + U_ASSERT_EQUALS(map.AsMapGet(0), 13) + U_ASSERT_EQUALS(map.AsMapGet(1), 14) + U_ASSERT_EQUALS(map.AsMapGet(U_CONSTANT_TO_PARAM("foo")), 13) + U_ASSERT_EQUALS(map.AsMapGet(U_CONSTANT_TO_PARAM("bar")), 14) + + check(fb, U_STRING_FROM_CONSTANT("{\"foo\":13,\"bar\":14}"), U_HEXDUMP("03666f6f036261720208050201020d0e0808042401")); + + // Write the json equivalent of: { vec: [ -100, "Fred", 4.0 ], foo: 100 } + + size = fb.encodeMap([&]() { + fb.Key(U_CONSTANT_TO_PARAM("vec")); + fb.Vector([&]() { + fb.Int(-100); + fb.String(U_CONSTANT_TO_PARAM("Fred")); + fb.Double(4.0); + }); + fb.UInt(U_CONSTANT_TO_PARAM("foo"), 100); + }); + + fb.setRoot(); + fb.AsMap(map); + + U_ASSERT_EQUALS(map.GetSize(), 2) + + map.AsMapGetKeys(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 2) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(0), "vec") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(1), "foo") + + map.AsMapGetValues(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 2) + U_ASSERT_EQUALS(vec.AsVectorGet(1), 100) + + U_ASSERT_EQUALS(map.AsMapGet(1), 100) + U_ASSERT_EQUALS(map.AsMapGet(U_CONSTANT_TO_PARAM("foo")), 100) + + map.AsMapGetVector(0, vec); + + U_ASSERT_EQUALS(vec.GetSize(), 3) + U_ASSERT_EQUALS(vec.AsVectorGet(0), -100) + U_ASSERT_EQUALS(vec.AsVectorGet(1), "Fred") + U_ASSERT_EQUALS(vec.AsVectorGet(2), 4.0) + + map.AsMapGetVector(U_CONSTANT_TO_PARAM("vec"), vec); + + U_ASSERT_EQUALS(vec.GetSize(), 3) + U_ASSERT_EQUALS(vec.AsVectorGet(0), -100) + U_ASSERT_EQUALS(vec.AsVectorGet(1), "Fred") + U_ASSERT_EQUALS(vec.AsVectorGet(2), 4.0) + + check(fb, U_STRING_FROM_CONSTANT("{\"vec\":[-100,\"Fred\",4.0],\"foo\":100}"), U_HEXDUMP("03766563044672656403000000640000000c0000000000804006140e03666f6f02200502010219642a08042401")); + + size = fb.encodeVector([&]() { + fb.String(U_CONSTANT_TO_PARAM("hello")); + fb.Map([&]() { + fb.UInt(U_CONSTANT_TO_PARAM("a"), 12); + fb.UInt(U_CONSTANT_TO_PARAM("b"), 4); + }); + fb.Vector([&]() { + fb.UInt(1); + fb.UInt(3); + }); + fb.Map([&]() { + fb.UInt(U_CONSTANT_TO_PARAM("a"), 12); + fb.UInt(U_CONSTANT_TO_PARAM("b"), 4); + }); + }); + + fb.setRoot(); + fb.AsVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 4) + U_ASSERT_EQUALS(vec.AsVectorGet(0), "hello") + + vec.AsVectorGetVector(2, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsVectorGet(0), 1) + U_ASSERT_EQUALS(vec0.AsVectorGet(1), 3) + + vec.AsVectorGetMap(1, map0); + + U_ASSERT_EQUALS(map0.GetSize(), 2) + + map0.AsMapGetKeys(vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(0), "a") + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), "b") + + map0.AsMapGetValues(vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsVectorGet(0), 12) + U_ASSERT_EQUALS(vec0.AsVectorGet(1), 4) + + vec.AsVectorGetMap(3, map0); + + U_ASSERT_EQUALS(map0.GetSize(), 2) + + map0.AsMapGetKeys(vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(0), "a") + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), "b") + + map0.AsMapGetValues(vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsVectorGet(0), 12) + U_ASSERT_EQUALS(vec0.AsVectorGet(1), 4) + + size = fb.encodeVector([&]() { + fb.UInt(1); + fb.Int(INT_MIN); + fb.UInt(2); + fb.UInt(UINT_MAX); + fb.Add(3.0); + fb.Add(true); + fb.String(U_CONSTANT_TO_PARAM("Hello")); + fb.String(U_CONSTANT_TO_PARAM("Hello!")); + fb.Add(); + fb.String(U_CONSTANT_TO_PARAM("a")); + fb.String(U_CONSTANT_TO_PARAM("b")); + fb.String(U_CONSTANT_TO_PARAM("a!")); + fb.String(U_CONSTANT_TO_PARAM("b!")); + fb.FixedTypedVector(vec1, 3); + fb.FixedTypedVector(vec1, 3); + fb.TypedVector(vec2, 2); + fb.TypedVector(vec3, 3); + vec3[1] = 2.3; + vec3[2] = 4.5; + fb.TypedVector(vec3, 2); + fb.TypedVector(vec3, 3); + fb.TypedVector(vec3, 4); + fb.FixedTypedVector(vec1, 2); + vec1[2] = 4; + fb.FixedTypedVector(vec1, 3); + fb.FixedTypedVector(vec1, 4); + fb.FixedTypedVector(vec1, 2); + fb.FixedTypedVector(vec1, 3); + fb.FixedTypedVector(vec1, 4); + fb.String(U_CONSTANT_TO_PARAM("hello")); + fb.Map([&]() { + fb.UInt(U_CONSTANT_TO_PARAM("a"), 12); + fb.UInt(U_CONSTANT_TO_PARAM("b"), 4); + }); + fb.Vector([&]() { + fb.UInt(1); + fb.UInt(3); + }); + vec1[0] = INT_MIN; + vec1[1] = INT_MAX; + fb.FixedTypedVector(vec1, 2); + vec1[0] = 0ULL; + vec1[1] = UINT_MAX; + fb.FixedTypedVector(vec1, 2); + fb.IndirectUInt(23); + fb.IndirectUInt(UINT_MAX); + fb.IndirectUInt(INT_MAX); + fb.IndirectUInt(UINT_MAX); + fb.IndirectFloat(3.5); + }); + + U_INTERNAL_ASSERT_EQUALS(size, 607) + + fb.setRoot(); + fb.AsVector(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 36) + U_ASSERT_EQUALS(vec.AsVectorGet(0), 1) + U_ASSERT_EQUALS(vec.AsVectorGet(1), INT_MIN) + U_ASSERT_EQUALS(vec.AsVectorGet(2), 2) + U_ASSERT_EQUALS(vec.AsVectorGet(3), UINT_MAX) + U_ASSERT_EQUALS(vec.AsVectorGet(4), 3.0) + U_ASSERT_EQUALS(vec.AsVectorGet(5), true) + U_ASSERT_EQUALS(vec.AsVectorGet(6), "Hello") + U_ASSERT_EQUALS(vec.AsVectorGet(7), "Hello!") + U_ASSERT_EQUALS(vec.AsVectorGet(9), "a") + U_ASSERT_EQUALS(vec.AsVectorGet(10), "b") + U_ASSERT_EQUALS(vec.AsVectorGet(11), "a!") + U_ASSERT_EQUALS(vec.AsVectorGet(12), "b!") + + vec.AsVectorGetFixedTypedVector(13, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 3) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(2), 3) + + vec.AsVectorGetFixedTypedVector(14, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 3) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(2), 3) + + vec.AsVectorGetTypedVector(15, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), false) + + vec.AsVectorGetTypedVector(16, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 3) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(2), 0.5) + + vec.AsVectorGetTypedVector(17, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), 2.3) + + vec.AsVectorGetTypedVector(18, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 3) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(2), 4.5) + + vec.AsVectorGetTypedVector(19, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 4) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(3), 5.6) + + vec.AsVectorGetFixedTypedVector(20, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), 2) + + vec.AsVectorGetFixedTypedVector(21, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 3) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(2), 4) + + vec.AsVectorGetFixedTypedVector(22, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 4) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(2), 4) + + vec.AsVectorGetFixedTypedVector(23, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), 2) + + vec.AsVectorGetFixedTypedVector(24, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 3) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(2), 4) + + vec.AsVectorGetFixedTypedVector(25, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 4) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(2), 4) + + U_ASSERT_EQUALS(vec.AsVectorGet(26), "hello") + + vec.AsVectorGetMap(27, map0); + + U_ASSERT_EQUALS(map0.GetSize(), 2) + + map0.AsMapGetKeys(vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(0), "a") + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), "b") + + map0.AsMapGetValues(vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsVectorGet(0), 12) + U_ASSERT_EQUALS(vec0.AsVectorGet(1), 4) + + vec.AsVectorGetVector(28, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsVectorGet(0), 1) + U_ASSERT_EQUALS(vec0.AsVectorGet(1), 3) + + vec.AsVectorGetFixedTypedVector(29, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(1), INT_MAX) + + vec.AsVectorGetFixedTypedVector(30, vec0); + + U_ASSERT_EQUALS(vec0.GetSize(), 2) + U_ASSERT_EQUALS(vec0.AsTypedOrFixedVectorGet(0), 0) + + U_ASSERT_EQUALS(vec.AsVectorGetIndirect(31), 23) + U_ASSERT_EQUALS(vec.AsVectorGetIndirect(32), UINT_MAX) + U_ASSERT_EQUALS(vec.AsVectorGetIndirect(33), INT_MAX) + U_ASSERT_EQUALS(vec.AsVectorGetIndirect(34), UINT_MAX) + U_ASSERT_EQUALS(vec.AsVectorGetIndirect(35), 3.5) + + size = fb.encodeMap([&]() { + fb.UInt(U_CONSTANT_TO_PARAM("a"), 1); + fb.UInt(U_CONSTANT_TO_PARAM("b"), 2); + fb.UInt(U_CONSTANT_TO_PARAM("c"), (uint64_t)UINT_MAX); + fb.Int(U_CONSTANT_TO_PARAM("d"), (uint64_t)INT_MIN); + fb.UInt(U_CONSTANT_TO_PARAM("e"), 1); + fb.UInt(U_CONSTANT_TO_PARAM("f"), 2); + fb.UInt(U_CONSTANT_TO_PARAM("g"), (uint64_t)UINT_MAX); + fb.UInt(U_CONSTANT_TO_PARAM("h"), 0); + fb.Add(U_CONSTANT_TO_PARAM("i"), 1.1); + fb.Add(U_CONSTANT_TO_PARAM("j"), 2.2); + fb.Add(U_CONSTANT_TO_PARAM("k"), U_CONSTANT_TO_PARAM("Hello")); + fb.Add(U_CONSTANT_TO_PARAM("l"), U_CONSTANT_TO_PARAM("Hello2")); + fb.Add(U_CONSTANT_TO_PARAM("m"), U_CONSTANT_TO_PARAM("Hello3")); + fb.Add(U_CONSTANT_TO_PARAM("n"), U_CONSTANT_TO_PARAM("Hello4")); + fb.Add(U_CONSTANT_TO_PARAM("o"), true); + fb.Add(U_CONSTANT_TO_PARAM("p"), false); + fb.Add(U_CONSTANT_TO_PARAM("q"), U_CONSTANT_TO_PARAM("Bla")); + fb.Add(U_CONSTANT_TO_PARAM("r"), U_CONSTANT_TO_PARAM("BlaBla")); + fb.IndirectInt(U_CONSTANT_TO_PARAM("u"), (uint64_t)INT_MAX); + fb.IndirectInt(U_CONSTANT_TO_PARAM("v"), (uint64_t)INT_MIN); + fb.IndirectUInt(U_CONSTANT_TO_PARAM("w"), 1); + fb.IndirectUInt(U_CONSTANT_TO_PARAM("x"), 2); + fb.IndirectUInt(U_CONSTANT_TO_PARAM("y"), (uint64_t)UINT_MAX); + fb.IndirectUInt(U_CONSTANT_TO_PARAM("z"), 0); + fb.IndirectFloat(U_CONSTANT_TO_PARAM("aa"), 1.1f); + fb.IndirectFloat(U_CONSTANT_TO_PARAM("ab"), 2.2f); + fb.IndirectUInt(U_CONSTANT_TO_PARAM("ac"), 1); + fb.IndirectUInt(U_CONSTANT_TO_PARAM("ad"), 2); + fb.FixedTypedVector(U_CONSTANT_TO_PARAM("ae"), vec1, 3); + fb.TypedVector(U_CONSTANT_TO_PARAM("af"), vec2, 2); + fb.FixedTypedVector(U_CONSTANT_TO_PARAM("ag"), vec3, 3); + fb.Add(U_CONSTANT_TO_PARAM("bk"), U_CONSTANT_TO_PARAM("ef")); + fb.Vector(U_CONSTANT_TO_PARAM("bm"), [&]() { + fb.UInt(1); + fb.UInt(3); + fb.UInt(4); + }); + fb.Vector(U_CONSTANT_TO_PARAM("bn"), [&]() { + fb.UInt(1); + fb.UInt(3); + fb.UInt(5); + }); + fb.Key(U_CONSTANT_TO_PARAM("map1")); + fb.Map(U_CONSTANT_TO_PARAM("bo"), [&]() { + fb.UInt(12); + }); + fb.Key(U_CONSTANT_TO_PARAM("map2")); + fb.Map(U_CONSTANT_TO_PARAM("bp"), [&]() { + fb.Add(true); + }); + }); + + U_INTERNAL_ASSERT_EQUALS(size, 632) + + fb.setRoot(); + fb.AsMap(map); + + U_ASSERT_EQUALS(map.GetSize(), 36) + + map.AsMapGetKeys(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 36) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(0), "a") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(1), "b") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(32), "bm") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(33), "bn") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(34), "map1") + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(35), "map2") + + map.AsMapGetValues(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 36) + U_ASSERT_EQUALS(vec.AsVectorGet(0), 1) + U_ASSERT_EQUALS(vec.AsVectorGet(1), 2) + U_ASSERT_EQUALS(vec.AsVectorGet(2), UINT_MAX) + U_ASSERT_EQUALS(vec.AsVectorGet(3), INT_MIN) + U_ASSERT_EQUALS(vec.AsVectorGet(4), 1) + U_ASSERT_EQUALS(vec.AsVectorGet(5), 2) + U_ASSERT_EQUALS(vec.AsVectorGet(6), UINT_MAX) + U_ASSERT_EQUALS(vec.AsVectorGet(7), 0) + U_ASSERT_EQUALS(vec.AsVectorGet(8), 1.1) + U_ASSERT_EQUALS(vec.AsVectorGet(9), 2.2) + U_ASSERT_EQUALS(vec.AsVectorGet(10), "Hello") + U_ASSERT_EQUALS(vec.AsVectorGet(11), "Hello2") + U_ASSERT_EQUALS(vec.AsVectorGet(12), "Hello3") + U_ASSERT_EQUALS(vec.AsVectorGet(13), "Hello4") + + map.AsMapGetVector(U_CONSTANT_TO_PARAM("bm"), vec); + + U_ASSERT_EQUALS(vec.GetSize(), 3) + U_ASSERT_EQUALS(vec.AsVectorGet(0), 1) + U_ASSERT_EQUALS(vec.AsVectorGet(1), 3) + U_ASSERT_EQUALS(vec.AsVectorGet(2), 4) + + map.AsMapGetVector(U_CONSTANT_TO_PARAM("bn"), vec); + + U_ASSERT_EQUALS(vec.GetSize(), 3) + U_ASSERT_EQUALS(vec.AsVectorGet(0), 1) + U_ASSERT_EQUALS(vec.AsVectorGet(1), 3) + U_ASSERT_EQUALS(vec.AsVectorGet(2), 5) + + map.AsMapGetMap(U_CONSTANT_TO_PARAM("map1"), map0); + + U_ASSERT_EQUALS(map0.GetSize(), 1) + + map0.AsMapGetKeys(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 1) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(0), "bo") + + map0.AsMapGetValues(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 1) + U_ASSERT_EQUALS(vec.AsVectorGet(0), 12) + + map.AsMapGetMap(U_CONSTANT_TO_PARAM("map2"), map0); + + U_ASSERT_EQUALS(map0.GetSize(), 1) + + map0.AsMapGetKeys(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 1) + U_ASSERT_EQUALS(vec.AsTypedOrFixedVectorGet(0), "bp") + + map0.AsMapGetValues(vec); + + U_ASSERT_EQUALS(vec.GetSize(), 1) + U_ASSERT_EQUALS(vec.AsVectorGet(0), true) + + Multiple().testFlatBuffer(); +} diff --git a/tests/ulib/test_string.cpp b/tests/ulib/test_string.cpp index 6a319429..32a77ff0 100644 --- a/tests/ulib/test_string.cpp +++ b/tests/ulib/test_string.cpp @@ -1515,6 +1515,7 @@ U_EXPORT main(int argc, char* argv[]) U_ASSERT( U_STRING_FROM_CONSTANT("-0.0").strtod() == -0.0 ) U_ASSERT( U_STRING_FROM_CONSTANT("1.89").strtod() == 1.89 ) U_ASSERT( U_STRING_FROM_CONSTANT("1e30").strtod() == 1e30 ) + U_ASSERT( U_STRING_FROM_CONSTANT("1000").strtod() == 1000.0 ) U_ASSERT( U_STRING_FROM_CONSTANT("1.2345").strtod() == 1.2345 ) U_ASSERT( U_STRING_FROM_CONSTANT("5e-324").strtod() == 5e-324 ) // Min subnormal positive double U_ASSERT( U_STRING_FROM_CONSTANT("-1E-10").strtod() == -1e-10 ) @@ -1967,11 +1968,11 @@ U_EXPORT main(int argc, char* argv[]) z = UStringExt::substitute(y, U_CONSTANT_TO_PARAM("uno"), U_CONSTANT_TO_PARAM("primo")); - U_ASSERT( z == " primo due tre quattro cinque \n" - " primo due tre quattro cinque \n" - " primo due tre quattro cinque \n" - " primo due tre quattro cinque \n" - " primo due tre quattro cinque \n") + U_ASSERT(z == " primo due tre quattro cinque \n" + " primo due tre quattro cinque \n" + " primo due tre quattro cinque \n" + " primo due tre quattro cinque \n" + " primo due tre quattro cinque \n") z = U_STRING_FROM_CONSTANT("uno primo due secondo tre terzo quattro quarto cinque quinto"); @@ -1983,11 +1984,31 @@ U_EXPORT main(int argc, char* argv[]) vec.clear(); - U_ASSERT( y == " primo secondo terzo quarto quinto \n" - " primo secondo terzo quarto quinto \n" - " primo secondo terzo quarto quinto \n" - " primo secondo terzo quarto quinto \n" - " primo secondo terzo quarto quinto \n") + U_ASSERT(y == " primo secondo terzo quarto quinto \n" + " primo secondo terzo quarto quinto \n" + " primo secondo terzo quarto quinto \n" + " primo secondo terzo quarto quinto \n" + " primo secondo terzo quarto quinto \n") + + z = U_STRING_FROM_CONSTANT("5 Bob Apples"); + + (void) vec.split(z); + + y = UStringExt::substituteIds(U_CONSTANT_TO_PARAM("$1 purchased $0 $2. Thanks $1!"), vec); + + vec.clear(); + + U_ASSERT_EQUALS(y, "Bob purchased 5 Apples. Thanks Bob!") + + z = U_STRING_FROM_CONSTANT("0 1 2 3 4 5 6 7 8 9 5 Bob Apples"); + + (void) vec.split(z); + + y = UStringExt::substituteIds(U_CONSTANT_TO_PARAM("$11 purchased $10 $12. Thanks $11!"), vec); + + vec.clear(); + + U_ASSERT_EQUALS(y, "Bob purchased 5 Apples. Thanks Bob!") y = U_STRING_FROM_CONSTANT("Hello\n\n");