From 350944c675b1202ac75376162fd4eb04edc0924c Mon Sep 17 00:00:00 2001 From: stefanocasazza Date: Tue, 24 Oct 2017 17:13:56 +0200 Subject: [PATCH] sync --- examples/IR/cquery.cpp | 2 +- examples/IR/ir_web.cpp | 8 +- examples/IR/posting.cpp | 10 +- examples/PEC_log/PEC_report_anomalie1.cpp | 2 +- examples/PEC_log/PEC_report_messaggi.cpp | 8 +- include/ulib/base/base.h | 2 + include/ulib/base/utility.h | 2 + include/ulib/command.h | 35 +- include/ulib/container/construct.h | 20 +- include/ulib/container/hash_map.h | 1018 ++++++++++------- include/ulib/container/vector.h | 19 +- include/ulib/db/cdb.h | 2 + include/ulib/file.h | 147 ++- include/ulib/json/value.h | 31 +- include/ulib/mime/header.h | 13 +- include/ulib/string.h | 40 +- include/ulib/utility/http2.h | 24 +- include/ulib/utility/uhttp.h | 5 - src/ulib/base/utility.c | 26 +- src/ulib/command.cpp | 67 +- src/ulib/container/hash_map.cpp | 987 +++++----------- src/ulib/container/vector.cpp | 18 - src/ulib/db/cdb.cpp | 168 ++- src/ulib/file.cpp | 132 +-- src/ulib/mime/header.cpp | 16 +- src/ulib/net/server/plugin/mod_http.cpp | 2 - src/ulib/net/server/plugin/mod_ssi.cpp | 2 +- .../net/server/plugin/usp/usp_translator.cpp | 146 ++- src/ulib/notifier.cpp | 14 +- src/ulib/string.cpp | 7 +- src/ulib/utility/dir_walk.cpp | 4 +- src/ulib/utility/http2.cpp | 60 +- src/ulib/utility/uhttp.cpp | 47 +- tests/base/test_sprintf.c | 9 +- tests/ulib/Makefile.am | 7 +- tests/ulib/Makefile.in | 98 +- tests/ulib/hash_map.test | 19 + tests/ulib/inp/base64.input | 1 - tests/ulib/ok/file_config.ok | 15 +- tests/ulib/ok/hash_map.ok | 75 ++ tests/ulib/test_file.cpp | 16 +- tests/ulib/test_file_config.cpp | 103 +- tests/ulib/test_hash_map.cpp | 236 ++++ tests/ulib/test_string.cpp | 3 + 44 files changed, 1851 insertions(+), 1815 deletions(-) create mode 100755 tests/ulib/hash_map.test create mode 100644 tests/ulib/ok/hash_map.ok create mode 100644 tests/ulib/test_hash_map.cpp diff --git a/examples/IR/cquery.cpp b/examples/IR/cquery.cpp index 66f1b26e..1cb7f046 100644 --- a/examples/IR/cquery.cpp +++ b/examples/IR/cquery.cpp @@ -55,7 +55,7 @@ void WeightWord::push() return; } - tbl->insertAfterFind(*UPosting::filename, item); + tbl->insertAfterFind(item); } if (vec == U_NULLPTR) U_NEW(UVector, vec, UVector); diff --git a/examples/IR/ir_web.cpp b/examples/IR/ir_web.cpp index 8ee8e4d7..d7c56f79 100644 --- a/examples/IR/ir_web.cpp +++ b/examples/IR/ir_web.cpp @@ -147,20 +147,20 @@ extern U_EXPORT void runDynamicPage_ir_web(int param); (void) UClientImage_Base::wbuffer->append((ref)); (void) UClientImage_Base::wbuffer->append( - U_CONSTANT_TO_PARAM("\" class=\"navilink\">help\n \n\n
\n \n\t\t \n
\n\n
\n per page\n
\n \n \n\n") + U_CONSTANT_TO_PARAM("\" class=\"navilink\">help\n \n\n
\n \n \n
\n\n
\n per page\n
\n \n \n\n") ); if (form_with_help) { (void) UClientImage_Base::wbuffer->append( - U_CONSTANT_TO_PARAM("\t
\n\t

Help

\n\n\t

What is This?

\n\n\t

This is a full-text search system. You can search for documents including some specified words.

\n\n\t

How to Use

\n\n\t

Input search phrase into the field at the top of the page. For example, if you search for documents including \"computer\", input the\n\t following.

\n\t
computer
\n\n\t

If you search for documents including both of \"network\" and \"socket\", input the following.

\n\t
network socket
\n\n\t

It is the same as the following.

\n\t
network AND socket
\n\n\t

If you search for documents including \"network\" followed by \"socket\", input the following.

\n\t
\"network socket\"
\n\n\t

If you search for documents including one or both of \"network\" and \"socket\", input the following.

\n\t
network OR socket
\n\n\t

If you search for documents including \"network\" but without \"socket\", input the following.

\n\t
network AND NOT socket
\n\n\t

For more complex query, you can use \"(\". Note that the priority of \"(\" is higher than that of \"AND\",\n\t \"OR\" and \"NOT\". So, the following is to search for documents including one of \"F1\", \"F-1\", \"Formula One\", and including\n\t one of \"champion\" and \"victory\".

\n\t
(F1 OR F-1 OR \"Formula One\") AND (champion OR victory)
\n\n\t

You can use DOS wildcard characters

\n\n\t

If you search for documents including some words beginning with \"inter\", input the following.

\n\t
inter*
\n\n\t

If you search for documents including some words ending with \"sphere\", input the following.

\n\t
*sphere
\n\n\t

If you search for documents matching some words matching \"?n*able\" (unable, unavoidable, inevitable, ...), input the following.

\n\t
?n*able
\n\n\t

Other Faculties

\n\n\t

\"[...] per page\" specifies the number of shown documents per page. If documents over one page correspond, you can move to another\n\t page via anchors of \"PREV\" and \"NEXT\" at the bottom of the page.

\n\n\t

Information

\n\n\t

See the project site for more detail.

\n\t
\n\n") + U_CONSTANT_TO_PARAM("
\n

Help

\n\n

What is This?

\n\n

This is a full-text search system. You can search for documents including some specified words.

\n\n

How to Use

\n\n

Input search phrase into the field at the top of the page. For example, if you search for documents including \"computer\", input the\n following.

\n
computer
\n\n

If you search for documents including both of \"network\" and \"socket\", input the following.

\n
network socket
\n\n

It is the same as the following.

\n
network AND socket
\n\n

If you search for documents including \"network\" followed by \"socket\", input the following.

\n
\"network socket\"
\n\n

If you search for documents including one or both of \"network\" and \"socket\", input the following.

\n
network OR socket
\n\n

If you search for documents including \"network\" but without \"socket\", input the following.

\n
network AND NOT socket
\n\n

For more complex query, you can use \"(\". Note that the priority of \"(\" is higher than that of \"AND\",\n \"OR\" and \"NOT\". So, the following is to search for documents including one of \"F1\", \"F-1\", \"Formula One\", and including\n one of \"champion\" and \"victory\".

\n
(F1 OR F-1 OR \"Formula One\") AND (champion OR victory)
\n\n

You can use DOS wildcard characters

\n\n

If you search for documents including some words beginning with \"inter\", input the following.

\n
inter*
\n\n

If you search for documents including some words ending with \"sphere\", input the following.

\n
*sphere
\n\n

If you search for documents matching some words matching \"?n*able\" (unable, unavoidable, inevitable, ...), input the following.

\n
?n*able
\n\n

Other Faculties

\n\n

\"[...] per page\" specifies the number of shown documents per page. If documents over one page correspond, you can move to another\n page via anchors of \"PREV\" and \"NEXT\" at the bottom of the page.

\n\n

Information

\n\n

See the project site for more detail.

\n
\n\n") ); } else { if (num_args == 0) { (void) UClientImage_Base::wbuffer->append( - U_CONSTANT_TO_PARAM("\t
\n\t\t

ULib search engine

\n\t\t
a full-text search system for communities
\n\t
\n\n") + U_CONSTANT_TO_PARAM("
\n

ULib search engine

\n
a full-text search system for communities
\n
\n\n") ); } else { @@ -176,7 +176,7 @@ extern U_EXPORT void runDynamicPage_ir_web(int param); if (UHTTP::num_item_tot == 0) { (void) UClientImage_Base::wbuffer->append( - U_CONSTANT_TO_PARAM("\t\t\t

Your search did not match any documents.

\n") + U_CONSTANT_TO_PARAM("

Your search did not match any documents.

\n") ); } else { diff --git a/examples/IR/posting.cpp b/examples/IR/posting.cpp index f9583549..5950067d 100644 --- a/examples/IR/posting.cpp +++ b/examples/IR/posting.cpp @@ -518,7 +518,7 @@ U_NO_EXPORT void UPosting::add() U_INTERNAL_ASSERT(*word) - bool present = (tbl_words ? tbl_words->find(*word) + bool present = (tbl_words ? tbl_words->find(*word) : ((URDB*)cdb_words)->find(*word)); if (present == false) @@ -540,11 +540,13 @@ U_NO_EXPORT void UPosting::add() if (tbl_words) { - word->duplicate(); // NB: need duplicate string because depends on mmap()'s content of document... - tbl_words_space += word->size() + posting->capacity(); - tbl_words->insertAfterFind(*word, *posting); + word->duplicate(); // NB: need duplicate string because depends on mmap()'s content of document... + + UHashMap::lkey = word->rep; + + tbl_words->insertAfterFind(*posting); } } else diff --git a/examples/PEC_log/PEC_report_anomalie1.cpp b/examples/PEC_log/PEC_report_anomalie1.cpp index 9c4fe92f..7283c0eb 100644 --- a/examples/PEC_log/PEC_report_anomalie1.cpp +++ b/examples/PEC_log/PEC_report_anomalie1.cpp @@ -299,7 +299,7 @@ public: ++nmsg; - table->insertAfterFind(Messaggio::msg->identifier, Messaggio::msg); + table->insertAfterFind(Messaggio::msg); } processLine(bnew); diff --git a/examples/PEC_log/PEC_report_messaggi.cpp b/examples/PEC_log/PEC_report_messaggi.cpp index 72d9334f..6f52eef9 100644 --- a/examples/PEC_log/PEC_report_messaggi.cpp +++ b/examples/PEC_log/PEC_report_messaggi.cpp @@ -246,9 +246,13 @@ public: { vc = new VCasellaIdCounter(); - key.duplicate(); // NB: need duplicate string because depends on mmap()'s content of document... + // NB: need duplicate string because depends on mmap()'s content of document... - table->insertAfterFind(key, vc); + key.duplicate(); + + UHashMap::lkey = key.rep; + + table->insertAfterFind(vc); } CasellaIdCounter* c; diff --git a/include/ulib/base/base.h b/include/ulib/base/base.h index 2c6d5c47..bd385b69 100644 --- a/include/ulib/base/base.h +++ b/include/ulib/base/base.h @@ -208,6 +208,8 @@ typedef int (*qcompare) (const void*,const void*); typedef void (*vPFpvpcpc) (void*,char*,char*); typedef void* (*pvPFpvpvs) (void*,const void*,size_t); +typedef uint32_t (*uPFpcu) (const char*,uint32_t); + typedef struct U_DATA { unsigned char* dptr; size_t dsize; diff --git a/include/ulib/base/utility.h b/include/ulib/base/utility.h index f23984bb..5bd9c6d9 100644 --- a/include/ulib/base/utility.h +++ b/include/ulib/base/utility.h @@ -681,6 +681,8 @@ static inline unsigned long u_atoi(const char* restrict s) #endif } +U_EXPORT int8_t u_log2(uint64_t value) __pure; + static inline unsigned u__octc2int(unsigned char c) { return ((c - '0') & 07); } /** diff --git a/include/ulib/command.h b/include/ulib/command.h index c062a501..50151781 100644 --- a/include/ulib/command.h +++ b/include/ulib/command.h @@ -39,10 +39,10 @@ public: void zero() { - envp = U_NULLPTR; - pathcmd = U_NULLPTR; - argv_exec = - envp_exec = U_NULLPTR; + envp = U_NULLPTR; + pathcmd = U_NULLPTR; + argv_exec = + envp_exec = U_NULLPTR; flag_expand = U_NOT_FOUND; ncmd = nenv = nfile = 0; } @@ -103,7 +103,7 @@ public: argv_exec[ncmd--] = U_NULLPTR; - U_INTERNAL_DUMP("ncmd = %d", ncmd) + U_INTERNAL_DUMP("ncmd = %u", ncmd) U_INTERNAL_ASSERT_RANGE(1,ncmd,U_ADD_ARGS) } @@ -118,14 +118,14 @@ public: argv_exec[++ncmd] = (char*) argument; argv_exec[ncmd+1] = U_NULLPTR; - U_INTERNAL_DUMP("ncmd = %d", ncmd) + U_INTERNAL_DUMP("ncmd = %u", ncmd) U_INTERNAL_ASSERT_RANGE(1,ncmd,U_ADD_ARGS) } - void setArgument(int n, const char* argument) + void setArgument(uint32_t n, const char* argument) { - U_TRACE(0, "UCommand::setArgument(%d,%S)", n, argument) + U_TRACE(0, "UCommand::setArgument(%u,%S)", n, argument) U_INTERNAL_ASSERT_RANGE(2,n,ncmd) U_INTERNAL_ASSERT_POINTER(argv_exec) @@ -145,9 +145,9 @@ public: argv_exec[ncmd] = (char*) argument; } - char* getArgument(int n) const __pure + char* getArgument(uint32_t n) const __pure { - U_TRACE(0, "UCommand::getArgument(%d)", n) + U_TRACE(0, "UCommand::getArgument(%u)", n) char* arg = (argv_exec ? argv_exec[n] : U_NULLPTR); @@ -156,7 +156,7 @@ public: U_RETURN(arg); } - void setNumArgument(int32_t n = 1, bool bfree = false); + void setNumArgument(uint32_t n = 1, bool bfree = false); // MANAGE FILE ARGUMENT @@ -168,15 +168,15 @@ public: U_INTERNAL_ASSERT_POINTER(argv_exec) U_INTERNAL_ASSERT(u_isText((const unsigned char*)pathfile, u__strlen(pathfile, __PRETTY_FUNCTION__))) - U_INTERNAL_DUMP("ncmd = %d", ncmd) + U_INTERNAL_DUMP("ncmd = %u", ncmd) U_INTERNAL_ASSERT_RANGE(2,nfile,ncmd) argv_exec[nfile] = (char*) pathfile; } - int32_t getNumArgument() const { return ncmd; } - int32_t getNumFileArgument() const { return nfile; } + uint32_t getNumArgument() const { return ncmd; } + uint32_t getNumFileArgument() const { return nfile; } UString getStringCommand() { return command; } UString getStringEnvironment() { return environment; } @@ -229,8 +229,8 @@ public: static void setTimeout(int seconds) { timeoutMS = (seconds * 1000); } - static int32_t setEnvironment(const UString& env, char**& envp); - static void freeEnvironment(char** _envp, int32_t n) { UMemoryPool::_free(_envp, n + 1, sizeof(char*)); } // NB: we consider the null terminator... + static uint32_t setEnvironment(const UString& env, char**& envp); + static void freeEnvironment(char** _envp, uint32_t n) { UMemoryPool::_free(_envp, n + 1, sizeof(char*)); } // NB: we consider the null terminator... // run command @@ -296,9 +296,8 @@ protected: char* pathcmd; char** argv_exec; char** envp_exec; - uint32_t flag_expand; - int32_t ncmd, nenv, nfile; UString command, environment; + uint32_t flag_expand, ncmd, nenv, nfile; void setCommand(); void freeCommand(); diff --git a/include/ulib/container/construct.h b/include/ulib/container/construct.h index c5a4f27b..a8ce114d 100644 --- a/include/ulib/container/construct.h +++ b/include/ulib/container/construct.h @@ -24,8 +24,7 @@ template inline void u_construct(const T** ptr, bool stream_loading) U_INTERNAL_ASSERT_POINTER(ptr) -// coverity[RESOURCE_LEAK] -#ifndef U_COVERITY_FALSE_POSITIVE +#ifndef U_COVERITY_FALSE_POSITIVE // coverity[RESOURCE_LEAK] if (stream_loading) U_NEW(T, *ptr, T(**ptr)); #endif } @@ -39,8 +38,7 @@ template inline void u_destroy(const T* ptr) { U_TRACE(0, "u_destroy(%p)", ptr) -// coverity[RESOURCE_LEAK] -#ifndef U_COVERITY_FALSE_POSITIVE +#ifndef U_COVERITY_FALSE_POSITIVE // coverity[RESOURCE_LEAK] if (ptr <= (const void*)0x0000ffff) U_ERROR("u_destroy(%p)", ptr); delete ptr; @@ -51,8 +49,7 @@ template inline void u_destroy(const T** ptr, uint32_t n) { U_TRACE(0, "u_destroy(%p,%u)", ptr, n) -// coverity[RESOURCE_LEAK] -#ifndef U_COVERITY_FALSE_POSITIVE +#ifndef U_COVERITY_FALSE_POSITIVE // coverity[RESOURCE_LEAK] for (uint32_t i = 0; i < n; ++i) { U_INTERNAL_DUMP("ptr[%u] = %p", i, ptr[i]) @@ -68,8 +65,7 @@ template <> inline void u_construct(const UStringRep** prep, bool stream_loading U_VAR_UNUSED(stream_loading) -// coverity[RESOURCE_LEAK] -#ifndef U_COVERITY_FALSE_POSITIVE +#ifndef U_COVERITY_FALSE_POSITIVE // coverity[RESOURCE_LEAK] ((UStringRep*)(*prep))->hold(); #endif } @@ -78,8 +74,7 @@ template <> inline void u_construct(const UStringRep* rep, uint32_t n) { U_TRACE(0, "u_construct(%p,%u)", rep, n) -// coverity[RESOURCE_LEAK] -#ifndef U_COVERITY_FALSE_POSITIVE +#ifndef U_COVERITY_FALSE_POSITIVE // coverity[RESOURCE_LEAK] ((UStringRep*)rep)->references += n; U_INTERNAL_DUMP("references = %d", rep->references + 1) @@ -88,10 +83,9 @@ template <> inline void u_construct(const UStringRep* rep, uint32_t n) template <> inline void u_destroy(const UStringRep* rep) { - U_TRACE(0, "u_destroy(%p)", rep) + U_TRACE(0, "u_destroy(%V)", rep) -// coverity[RESOURCE_LEAK] -#ifndef U_COVERITY_FALSE_POSITIVE +#ifndef U_COVERITY_FALSE_POSITIVE // coverity[RESOURCE_LEAK] ((UStringRep*)rep)->release(); #endif } diff --git a/include/ulib/container/hash_map.h b/include/ulib/container/hash_map.h index 09dc7f4e..cf7fee56 100644 --- a/include/ulib/container/hash_map.h +++ b/include/ulib/container/hash_map.h @@ -11,91 +11,54 @@ // // ============================================================================ -#ifndef ULIB_HASH_MAP_H -#define ULIB_HASH_MAP_H 1 +#ifndef ULIB_HASHMAP_H +#define ULIB_HASHMAP_H 1 #include -typedef UVector UVectorUString; +/** + * Modified, highly optimized Robin Hood Hashtable + * + * Algorithm from https://github.com/martinus/robin-hood-hashing/ + */ -typedef bool (*bPFprpv) (UStringRep*,void*); -typedef uint32_t (*uPFpcu) (const char*,uint32_t); -typedef bool (*bPFptpcu) (UHashMap*,const char*,uint32_t); +#define U_MAX_LOAD_FACTOR 0.90f // 0.50f +#define U_IS_BUCKET_TAKEN_MASK (1 << 7) -class UCDB; -class UHTTP; -class UHTTP2; -class UDirWalk; -class WeightWord; -class UMimeHeader; -class UFileConfig; -class UNoCatPlugIn; -class UCertificate; +template class UHashMap; -template class UJsonTypeHandler; -template class URDBObjectHandler; +typedef bool (*bPFpt)(UHashMap*); #if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX11) template class UHashMapAnonIter; #endif +class UHTTP2; +class WeightWord; + class U_NO_EXPORT UHashMapNode { public: - // Check for memory error - U_MEMORY_TEST - - // Allocator e Deallocator - U_MEMORY_ALLOCATOR - U_MEMORY_DEALLOCATOR - const void* elem; const UStringRep* key; - UHashMapNode* next; uint32_t hash; - UHashMapNode(const UStringRep* _key, const void* _elem, UHashMapNode* _next, uint32_t _hash) : elem(_elem), key(_key), next(_next), hash(_hash) + void set(); + void reset() { - U_TRACE_REGISTER_OBJECT(0, UHashMapNode, "%V,%p,%p,%u", _key, _elem, _next, _hash) + U_TRACE_NO_PARAM(0, "UHashMapNode::reset()") - ((UStringRep*)_key)->hold(); // NB: we increases the reference string... - } - - UHashMapNode(UHashMapNode* n, UHashMapNode* _next) : elem(n->elem), key(n->key), next(_next), hash(n->hash) - { - U_TRACE_REGISTER_OBJECT(0, UHashMapNode, "%p,%p", n, _next) - - ((UStringRep*)key)->hold(); // NB: we increases the reference string... - } - - ~UHashMapNode() - { - U_TRACE_UNREGISTER_OBJECT(0, UHashMapNode) + U_INTERNAL_DUMP("key = %V", key) ((UStringRep*)key)->release(); // NB: we decreases the reference string... } - UHashMapNode& operator=(const UHashMapNode& n) - { - U_TRACE(0, "UHashMapNode::operator=(%p)", &n) + static uint32_t size() { return sizeof(uint32_t)+(sizeof(void*)*2); } - U_MEMORY_TEST_COPY(n) - - elem = n.elem; - key = n.key; - next = n.next; - hash = n.hash; - - return *this; - } - -#if defined(U_STDCPP_ENABLE) && defined(DEBUG) - U_EXPORT const char* dump(bool reset) const; -#endif +private: + U_DISALLOW_COPY_AND_ASSIGN(UHashMapNode) }; -template class UHashMap; - template <> class U_EXPORT UHashMap { public: @@ -108,9 +71,23 @@ public: // Costruttori e distruttore - UHashMap(uint32_t n, bool ignore_case); + UHashMap(uint32_t n = 64, bPFpt fset_index = setIndex) + { + U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%p", n, fset_index) - UHashMap(uint32_t n = 64, bPFptpcu _set_index = setIndex); + set_index = fset_index; + + init(n); + } + + UHashMap(uint32_t n, bool ignore_case) + { + U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%b", n, ignore_case) + + set_index = (ignore_case ? setIndexIgnoreCase : setIndex); + + init(n); + } ~UHashMap() { @@ -123,6 +100,34 @@ public: // size and capacity + void allocate(uint32_t n) + { + U_TRACE(0, "UHashMap::allocate(%u)", n) + + U_CHECK_MEMORY + + if (_capacity) + { + U_INTERNAL_ASSERT_DIFFERS(_capacity, n) + + _deallocate(); + } + + _allocate(n); + } + + void deallocate() + { + U_TRACE_NO_PARAM(0, "UHashMap::deallocate()") + + if (_capacity) + { + _deallocate(); + + _capacity = 0; + } + } + uint32_t size() const { U_TRACE_NO_PARAM(0, "UHashMap::size()") @@ -137,6 +142,13 @@ public: U_RETURN(_capacity); } + uint32_t getMask() const + { + U_TRACE_NO_PARAM(0, "UHashMap::getMask()") + + U_RETURN(mask); + } + bool empty() const { U_TRACE_NO_PARAM(0, "UHashMap::empty()") @@ -155,7 +167,7 @@ public: set_index = (flag ? setIndexIgnoreCase : setIndex); } - void setIndexFunction(bPFptpcu fset_index) + void setIndexFunction(bPFpt fset_index) { U_TRACE(0, "UHashMap::setIndexFunction(%p)", fset_index) @@ -168,147 +180,254 @@ public: // ricerche - bool find(const UString& _key) + bool find(const UString& k) { - U_TRACE(0, "UHashMap::find(%V)", _key.rep) + U_TRACE(0, "UHashMap::find(%V)", k.rep) - lookup(_key); + lkey = k.rep; - if (node) U_RETURN(true); + if (lookup()) U_RETURN(true); U_RETURN(false); } - bool find(const char* key, uint32_t keylen); - - // set/get methods - - void* operator[](const char* _key) + bool find(const char* k, uint32_t klen) { - U_TRACE(0, "UHashMap::operator[](%S)", _key) + U_TRACE(0, "UHashMap::find(%.*S,%u)", klen, k, klen) - U_INTERNAL_ASSERT_POINTER(pkey) + setKey(k, klen); - pkey->str = _key; - pkey->_length = u__strlen(_key, __PRETTY_FUNCTION__); + if (lookup()) U_RETURN(true); - return at(pkey); + U_RETURN(false); } - void* operator[](const UString& _key) { return at(_key.rep); } - void* operator[](const UStringRep* _key) { return at(_key); } + // get methods const void* elem() const { return node->elem; } const UString getKey() const { return UString(node->key); } const UStringRep* key() const { return node->key; } - template T* get(const UString& _key) + void* at(const UString& k) { return (lkey = k.rep, at()); } + void* at(const UStringRep* k) { return (lkey = k, at()); } + void* at(const char* k, uint32_t klen) { return (setKey(k, klen), at()); } + + void* operator[](const char* k) { return (setKey(k, u__strlen(k, __PRETTY_FUNCTION__)), at()); } + 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)", _key.rep) + U_TRACE(0, "UHashMap::get(%V)", k.rep) - return (T*) operator[](_key); - } - - // sets a field, overwriting any existing value - - void insert(const UString& _key, const void* _elem) - { - U_TRACE(0, "UHashMap::insert(%V,%p)", _key.rep, _elem) - - lookup(_key); - - insertAfterFind(_key.rep, _elem); + return (T*) operator[](k); } // after called find() (don't make the lookup) - void insertAfterFind(const UString& _key, const void* _elem) { insertAfterFind(_key.rep, _elem); } - void insertAfterFind(const UStringRep* _key, const void* _elem); - void eraseAfterFind(); - void replaceAfterFind(const void* _elem) + void replaceAfterFind(const void* e) { node->elem = e; } + void insertAfterFind(const void* e) { - U_TRACE(0, "UHashMap::replaceAfterFind(%p)", _elem) + U_TRACE(0, "UHashMap::insertAfterFind(%p)", e) - node->elem = _elem; + lelem = e; + + ((UStringRep*)lkey)->hold(); // NB: we increases the reference string... + + insertAfterFind(); } - void replaceKey(const UString& key); + void insert(const UString& k, const void* e) + { + U_TRACE(0, "UHashMap::insert(%V,%p)", k.rep, e) - void* erase(const char* _key); - void* erase(const UString& _key) { return erase(_key.rep); } - void* erase(const UStringRep* _key); + lkey = k.rep; - // make room for a total of n element + if (lookup()) replaceAfterFind(e); + else insertAfterFind(e); + } - void reserve( uint32_t n); - void allocate(uint32_t n); + void* erase(const UString& k) { return (lkey = k.rep, erase()); } + void* erase(const UStringRep* k) { return (lkey = k, erase()); } - // Traverse the hash table for all entry + void* erase(const char* k) + { + U_TRACE(0, "UHashMap::erase(%S)", k) - UHashMapNode* first(); + setKey(k, u__strlen(k, __PRETTY_FUNCTION__)); - // We need to pass the pointer because we can lost the internal pointer between the call... + return erase(); + } - bool next(); - UHashMapNode* next(UHashMapNode* node); + void setNodePointer() { setNodePointer(table, index); } + void setNodePointer(uint32_t idx) const { setNodePointer(table, idx); } + + static void setNodePointer(char* table, uint32_t idx) { node = (UHashMapNode*)(table + (idx * UHashMapNode::size())); } + + // traverse the hash table for all entry + + bool first() + { + U_TRACE_NO_PARAM(0, "UHashMap::first()") + + U_INTERNAL_DUMP("_length = %u", _length) + + if (_length) + { + for (index = 0; index < _capacity; ++index) + { + if ((info[index] & U_IS_BUCKET_TAKEN_MASK) != 0) + { + setNodePointer(); + + U_RETURN(true); + } + } + } + + U_RETURN(false); + } + + bool next() + { + U_TRACE_NO_PARAM(0, "UHashMap::next()") + + U_INTERNAL_DUMP("index = %u", index) + + for (++index; index < _capacity; ++index) + { + if ((info[index] & U_IS_BUCKET_TAKEN_MASK) != 0) + { + setNodePointer(); + + U_RETURN(true); + } + } + + U_RETURN(false); + } + + UHashMapNode* firstNode() { return (first() ? node : U_NULLPTR); } + UHashMapNode* nextNode() { return ( next() ? node : U_NULLPTR); } // call function for all entry - void callForAllEntry(bPFprpv function); + void callForAllEntry(vPFprpv function) + { + U_TRACE(0, "UHashMap::callForAllEntry(%p)", function) + + U_INTERNAL_DUMP("_length = %u", _length) + + for (uint32_t idx = 0; idx < _capacity; ++idx) + { + if ((info[idx] & U_IS_BUCKET_TAKEN_MASK) != 0) + { + setNodePointer(idx); + + function((UStringRep*)node->key, (void*)node->elem); + } + } + } + + void callForAllEntry(bPFprpv function) + { + U_TRACE(0, "UHashMap::callForAllEntry(%p)", function) + + U_INTERNAL_DUMP("_length = %u", _length) + + for (uint32_t idx = 0; idx < _capacity; ++idx) + { + if ((info[idx] & U_IS_BUCKET_TAKEN_MASK) != 0) + { + setNodePointer(idx); + + if (function((UStringRep*)node->key, (void*)node->elem) == false) return; + } + } + } + + void getKeys(UVector& vec) + { + U_TRACE(0, "UHashMap::getKeys(%p)", &vec) + + pvec = &vec; + + callForAllEntry(geyKey); + } + + void callForAllEntrySorted(vPFprpv function) + { + U_TRACE(0, "UHashMap::callForAllEntrySorted(%p)", function) + + if (_length < 2) callForAllEntry(function); + else _callForAllEntrySorted(function); + } + void callForAllEntrySorted(bPFprpv function) { U_TRACE(0, "UHashMap::callForAllEntrySorted(%p)", function) - U_INTERNAL_DUMP("_length = %u", _length) - - if (_length < 2) - { - callForAllEntry(function); - - return; - } - - _callForAllEntrySorted(function); + if (_length < 2) callForAllEntry(function); + else _callForAllEntrySorted(function); } -#if defined(U_STDCPP_ENABLE) && defined(DEBUG) + void callWithDeleteForAllEntry(bPFprpv function) + { + U_TRACE(0, "UHashMap::callWithDeleteForAllEntry(%p)", function) + + U_INTERNAL_DUMP("_length = %u", _length) + + U_INTERNAL_ASSERT_MAJOR(_length, 0) + + for (uint32_t idx = 0; idx < _capacity; ++idx) + { + if ((info[idx] & U_IS_BUCKET_TAKEN_MASK) != 0) + { + setNodePointer(idx); + + if (function((UStringRep*)node->key, (void*)node->elem)) + { + index = idx; + + eraseAfterFind(); + } + } + } + + U_INTERNAL_DUMP("_length = %u", _length) + } + +#ifdef DEBUG +# ifdef U_STDCPP_ENABLE const char* dump(bool reset) const; +# endif + bool invariant(); + bool checkAt(const UStringRep* k, const void* e); #endif // STREAMS + static UHashMapNode* node; static bool istream_loading; + static uint32_t index, lhash; + static const UStringRep* lkey; protected: - bPFptpcu set_index; - UHashMapNode* node; - UHashMapNode** table; - uint32_t _capacity, _length, hash; -public: - uint32_t index; -protected: - static UStringRep* pkey; + char* table; + uint8_t* info; + bPFpt set_index; + uint32_t _capacity, _length, mask, max_num_num_elements_allowed; -#ifdef DEBUG - bool check_memory() const; // check all element -#endif + static uint8_t linfo; + static const void* lelem; + static UVector* pvec; + + void increase_size(); // allocate and deallocate methods - void _allocate(uint32_t n) - { - U_TRACE(0, "UHashMap::_allocate(%u)", n) - - U_CHECK_MEMORY - - table = (UHashMapNode**) UMemoryPool::_malloc(&n, sizeof(UHashMapNode*), true); - _capacity = n; - - // Must be a power of 2, It's done this way because bitwise-and is an inexpensive operation, whereas integer modulo (%) is quite heavy - - U_INTERNAL_ASSERT_EQUALS(_capacity & (_capacity-1), 0) - } + void _allocate(uint32_t n); void _deallocate() { @@ -318,19 +437,7 @@ protected: U_INTERNAL_ASSERT_MAJOR(_capacity, 1) - UMemoryPool::_free(table, _capacity, sizeof(UHashMapNode*)); - } - - void deallocate() - { - U_TRACE_NO_PARAM(0, "UHashMap::deallocate()") - - if (_capacity) - { - _deallocate(); - - _capacity = 0; - } + UMemoryPool::_free(info, _capacity, 1+UHashMapNode::size()); } void init(uint32_t n) @@ -339,82 +446,176 @@ protected: U_INTERNAL_DUMP("this = %p", this) - node = U_NULLPTR; + _length = 0; _allocate(n); - - _length = - hash = - index = 0; } - // Find a elem in the array with - - void* at(const UStringRep* _key) + static void setKey(const char* k, uint32_t klen) { - U_TRACE(0, "UHashMap::at(%V)", _key) + U_TRACE(0, "UHashMap::setKey(%.*S,%u)", klen, k, klen) - lookup(_key); + U_INTERNAL_ASSERT_POINTER(k) + U_INTERNAL_ASSERT_MAJOR(klen, 0) + U_INTERNAL_ASSERT_POINTER(UString::pkey) - if (node) U_RETURN((void*)node->elem); + lkey = UString::pkey; + + ((UStringRep*)lkey)->str = k; + ((UStringRep*)lkey)->_length = klen; + } + + void putNode() + { + U_TRACE_NO_PARAM(0, "UHashMap::putNode()") + + U_INTERNAL_DUMP("linfo = %u info[%u] = %u", linfo, index, info[index]) + + info[index] = linfo; + + setNodePointer(); + + node->set(); + + U_ASSERT(checkAt(lkey, lelem)) + } + + void swapInfo() + { + U_TRACE_NO_PARAM(0, "UHashMap::swapInfo()") + + U_INTERNAL_ASSERT_MAJOR(linfo, info[index]) + + uint8_t tmp = linfo; + linfo = info[index]; + info[index] = tmp; + + U_INTERNAL_DUMP("linfo = %u info[%u] = %u", linfo, index, info[index]) + } + + void swapNode(); + void insertAfterFind(); + void swapNodeInResize(); + + // Find a elem in the array with key + + bool lookup(); + bool lookup(const UString& k) { return (lkey = k.rep, lookup()); } + bool lookup(const UStringRep* k) { return (lkey = k, lookup()); } + + void* at() + { + U_TRACE_NO_PARAM(0, "UHashMap::at()") + + if (lookup()) U_RETURN((void*)node->elem); U_RETURN((void*)U_NULLPTR); } - void* at(const char* _key, uint32_t keylen) + void* erase() { - U_TRACE(0, "UHashMap::at(%.*S,%u)", keylen, _key, keylen) + U_TRACE_NO_PARAM(0, "UHashMap::erase()") - U_INTERNAL_ASSERT_POINTER(pkey) - U_INTERNAL_ASSERT_POINTER(_key) - U_INTERNAL_ASSERT_MAJOR(keylen, 0) + if (lookup()) + { + lelem = node->elem; - pkey->str = _key; - pkey->_length = keylen; + eraseAfterFind(); - return at(pkey); + U_RETURN((void*)lelem); + } + + U_RETURN((void*)U_NULLPTR); } - void getKeys(UVector& vec); - - void lookup(const UString& keyr) { return lookup(keyr.rep); } - void lookup(const UStringRep* keyr); - - void _eraseAfterFind(); - void _callForAllEntrySorted(bPFprpv function); - - static void _setIndex(UHashMap* pthis) + static void geyKey(UStringRep* k, void* value) { - U_TRACE(0, "UHashMap::_setIndex(%p)", pthis) + U_TRACE(0, "UHashMap::geyKey(%V,%p)", k, value) - U_INTERNAL_DUMP("pthis->hash = %u", pthis->hash) - - U_INTERNAL_ASSERT_MAJOR(pthis->hash, 0) - U_INTERNAL_ASSERT_EQUALS(pthis->_capacity & (pthis->_capacity-1), 0) // Must be a power of 2 - - pthis->index = pthis->hash & (pthis->_capacity-1); - - U_INTERNAL_ASSERT_EQUALS(pthis->index, pthis->hash % pthis->_capacity) + pvec->UVector::push(node->key); } - static bool setIndex(UHashMap* pthis, const char* _key, uint32_t keylen) + void getKeysSort(UVector& vec) { - U_TRACE(0, "UHashMap::setIndex(%p,%.*S,%u)", pthis, keylen, _key, keylen) + U_TRACE(0, "UHashMap::getKeysSort(%p)", &vec) - pthis->hash = u_hash((unsigned char*)_key, keylen); + U_INTERNAL_ASSERT_MAJOR(_length, 1) - _setIndex(pthis); + getKeys(vec); + + U_ASSERT_EQUALS(_length, vec.size()) + + vec.sort(ignoreCase()); + } + + void _callForAllEntrySorted(vPFprpv function) + { + U_TRACE(0, "UHashMap::_callForAllEntrySorted(%p)", function) + + UVector vkey(_length); + + getKeysSort(vkey); + + for (uint32_t i = 0, n = _length; i < n; ++i) + { + UStringRep* r = vkey.UVector::at(i); + + (void) lookup(r); + + function(r, (void*)node->elem); + } + } + + void _callForAllEntrySorted(bPFprpv function) + { + U_TRACE(0, "UHashMap::_callForAllEntrySorted(%p)", function) + + UVector vkey(_length); + + getKeysSort(vkey); + + for (uint32_t i = 0, n = _length; i < n; ++i) + { + UStringRep* r = vkey.UVector::at(i); + + (void) lookup(r); + + if (function(r, (void*)node->elem) == false) return; + } + } + + static void setIdx(UHashMap* pthis) + { + U_TRACE(0, "UHashMap::setIdx(%p)", pthis) + + U_INTERNAL_DUMP("lhash = %u", lhash) + + U_INTERNAL_ASSERT_MAJOR(lhash, 0) + U_INTERNAL_ASSERT_EQUALS(pthis->_capacity & pthis->mask, 0) // Must be a power of 2 + + index = lhash & pthis->mask; + + U_INTERNAL_ASSERT_EQUALS(index, lhash % pthis->_capacity) + } + + static bool setIndex(UHashMap* pthis) + { + U_TRACE(0, "UHashMap::setIndex(%p)", pthis) + + lhash = u_hash((unsigned char*)U_STRING_TO_PARAM(*lkey)); + + setIdx(pthis); U_RETURN(false); } - static bool setIndexIgnoreCase(UHashMap* pthis, const char* _key, uint32_t keylen) + static bool setIndexIgnoreCase(UHashMap* pthis) { - U_TRACE(0, "UHashMap::setIndexIgnoreCase(%p,%.*S,%u)", pthis, keylen, _key, keylen) + U_TRACE(0, "UHashMap::setIndexIgnoreCase(%p)", pthis) - pthis->hash = u_hash_ignore_case((unsigned char*)_key, keylen); + lhash = u_hash_ignore_case((unsigned char*)U_STRING_TO_PARAM(*lkey)); - _setIndex(pthis); + setIdx(pthis); U_RETURN(true); } @@ -422,20 +623,20 @@ protected: private: U_DISALLOW_COPY_AND_ASSIGN(UHashMap) - friend class ULib; - friend class UCDB; - friend class UHTTP; friend class UHTTP2; - friend class UValue; - friend class UString; - friend class UDirWalk; friend class WeightWord; - friend class UFileConfig; - friend class UCertificate; - - template friend class UJsonTypeHandler; + friend class UHashMapNode; }; +inline void UHashMapNode::set() +{ + U_TRACE_NO_PARAM(0, "UHashMapNode::set()") + + elem = UHashMap::lelem; + key = UHashMap::lkey; + hash = UHashMap::lhash; +} + template class U_EXPORT UHashMap : public UHashMap { public: @@ -444,9 +645,9 @@ public: U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%b", n, ignore_case) } - UHashMap(uint32_t n = 64, bPFptpcu _set_index = setIndex) : UHashMap(n, _set_index) + UHashMap(uint32_t n = 64, bPFpt fset_index = setIndex) : UHashMap(n, fset_index) { - U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%p", n, _set_index) + U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%p", n, fset_index) } ~UHashMap() @@ -456,6 +657,25 @@ public: clear(); } + T* elem() const { return (T*) UHashMap::elem(); } + + T* operator[](const char* k) { return (T*) UHashMap::operator[](k); } + T* operator[](const UString& k) { return (T*) UHashMap::operator[](k); } + T* operator[](const UStringRep* k) { return (T*) UHashMap::operator[](k); } + + T* erase(const char* k) { return (T*) UHashMap::erase(k); } + T* erase(const UString& k) { return (T*) UHashMap::erase(k.rep); } + T* erase(const UStringRep* k) { return (T*) UHashMap::erase(k); } + + void eraseAfterFind() + { + U_TRACE_NO_PARAM(0, "UHashMap::eraseAfterFind()") + + u_destroy((T*)node->elem); + + UHashMap::eraseAfterFind(); + } + #if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX11) UHashMapAnonIter begin() { return UHashMapAnonIter(this, 0); } UHashMapAnonIter end() { return UHashMapAnonIter(this, _length); } @@ -472,120 +692,65 @@ public: } #endif - T* erase(const char* _key) { return (T*) UHashMap::erase(_key); } - T* erase(const UString& _key) { return (T*) UHashMap::erase(_key.rep); } - T* erase(const UStringRep* _key) { return (T*) UHashMap::erase(_key); } - - T* elem() const { return (T*) UHashMap::elem(); } - - T* operator[](const char* _key) { return (T*) UHashMap::operator[](_key); } - T* operator[](const UString& _key) { return (T*) UHashMap::operator[](_key); } - T* operator[](const UStringRep* _key) { return (T*) UHashMap::operator[](_key); } - - void eraseAfterFind() + void insertAfterFind(const T* e) { - U_TRACE_NO_PARAM(0, "UHashMap::eraseAfterFind()") + U_TRACE(0, "UHashMap::insertAfterFind(%p)", e) - U_INTERNAL_ASSERT_POINTER(node) + u_construct(&e, istream_loading); - u_destroy((const T*)node->elem); - - UHashMap::eraseAfterFind(); + UHashMap::insertAfterFind(e); } - void insertAfterFind(const UStringRep* _key, const T* _elem) + void replaceAfterFind(const T* e) { - U_TRACE(0, "UHashMap::insertAfterFind(%V,%p)", _key, _elem) + U_TRACE(0, "UHashMap::replaceAfterFind(%p)", e) - u_construct(&_elem, istream_loading); + u_construct(&e, false); - if (node == U_NULLPTR) UHashMap::insertAfterFind(_key, _elem); - else - { - u_destroy((const T*)node->elem); + u_destroy((T*)node->elem); - node->elem = _elem; - } + UHashMap::replaceAfterFind(e); } - void insertAfterFind(const UString& _key, const T* _elem) { insertAfterFind(_key.rep, _elem); } - - void replaceAfterFind(const T* _elem) + void insert(const UStringRep* k, const T* e) { - U_TRACE(0, "UHashMap::replaceAfterFind(%p)", _elem) + U_TRACE(0, "UHashMap::insert(%V,%p)", k, e) - U_INTERNAL_ASSERT_POINTER(node) - - u_construct(&_elem, false); - - u_destroy((const T*)node->elem); - - UHashMap::replaceAfterFind(_elem); + if (UHashMap::lookup(k)) replaceAfterFind(e); + else insertAfterFind(e); } - // sets a field, overwriting any existing value + void insert(const UString& k, const T* e) { return insert(k.rep, e); } - void insert(const UStringRep* _key, const T* _elem) - { - U_TRACE(0, "UHashMap::insert(%V,%p)", _key, _elem) + // find a elem in the array with key - UHashMap::lookup(_key); - - insertAfterFind(_key, _elem); - } - - void insert(const UString& _key, const T* _elem) - { - U_TRACE(0, "UHashMap::insert(%V,%p)", _key.rep, _elem) - - UHashMap::lookup(_key); - - insertAfterFind(_key.rep, _elem); - } - - // find a elem in the array with - - T* at(const UString& _key) { return (T*) UHashMap::at(_key.rep); } - T* at(const UStringRep* keyr) { return (T*) UHashMap::at(keyr); } - T* at(const char* _key, uint32_t keylen) { return (T*) UHashMap::at(_key, keylen); } + T* at(const UString& k) { return (T*) UHashMap::at(k.rep); } + T* at(const UStringRep* k) { return (T*) UHashMap::at(k); } + T* at(const char* k, uint32_t klen) { return (T*) UHashMap::at(k, klen); } void clear() // erase all element { U_TRACE_NO_PARAM(0+256, "UHashMap::clear()") - U_INTERNAL_ASSERT(check_memory()) - - U_INTERNAL_DUMP("_length = %u", _length) - if (_length) { - T* _elem; - UHashMapNode* _node; - UHashMapNode* _next; - UHashMapNode** ptr; - UHashMapNode** _end; + U_INTERNAL_DUMP("_length = %u", _length) - for (_end = (ptr = table) + _capacity; ptr < _end; ++ptr) + for (uint32_t idx = 0; idx < _capacity; ++idx) { - if (*ptr) + if ((info[idx] & U_IS_BUCKET_TAKEN_MASK) != 0) { - _node = *ptr; + setNodePointer(idx); - do { - _next = _node->next; - _elem = (T*)_node->elem; + node->reset(); - if (_elem) u_destroy(_elem); - - delete _node; - } - while ((_node = _next)); - - *ptr = U_NULLPTR; + u_destroy((T*)node->elem); } } _length = 0; + + (void) U_SYSCALL(memset, "%p,%d,%u", info, 0, _capacity); } } @@ -595,37 +760,20 @@ public: U_INTERNAL_DUMP("_length = %u", _length) - const T* _elem; - UHashMapNode** ptr; - UHashMapNode** _end; - UHashMapNode* _node; - UHashMapNode** pnode; + U_INTERNAL_ASSERT_MAJOR(_length, 0) - for (_end = (ptr = table) + _capacity; ptr < _end; ++ptr) + for (uint32_t idx = 0; idx < _capacity; ++idx) { - if (*ptr) + if ((info[idx] & U_IS_BUCKET_TAKEN_MASK) != 0) { - _node = *(pnode = ptr); + setNodePointer(idx); - do { - _elem = (const T*)_node->elem; + if (function((UStringRep*)node->key, (void*)node->elem)) + { + index = idx; - if (function((UStringRep*)_node->key, (void*)_elem)) - { - *pnode = _node->next; // we remove it from the list collisions - - u_destroy(_elem); - - delete _node; - - --_length; - - continue; - } - - pnode = &(*pnode)->next; + eraseAfterFind(); } - while ((_node = *pnode)); } } @@ -640,44 +788,18 @@ public: clear(); - if (t._length) + if (t.first()) { - const T* _elem; - UHashMapNode* _node; - UHashMapNode* _next; - UHashMapNode** ptr1; - UHashMapNode** end1; + uint32_t idx; - allocate(t._capacity); + if (_capacity != t._capacity) allocate(t._capacity); - UHashMapNode** ptr = table; + do { + idx = index; - for (end1 = (ptr1 = t.table) + t._capacity; ptr1 < end1; ++ptr1, ++ptr) - { - if (*ptr1) - { - _node = *ptr1; - - U_INTERNAL_ASSERT_EQUALS(*ptr, U_NULLPTR) - - do { - U_NEW(UHashMapNode, *ptr, UHashMapNode(_node, *ptr)); // we place it in the list collisions - - _elem = (const T*) (*ptr)->elem; - - U_INTERNAL_DUMP("_elem = %p", _elem) - - U_ASSERT_EQUALS(_elem, t[_node->key]) - - u_construct(&_elem, false); - - _next = _node->next; - } - while ((_node = _next)); - } + insert(t.key(), t.elem()); } - - _length = t._length; + while (index = idx, t.next()); } U_INTERNAL_DUMP("_length = %u", _length) @@ -700,9 +822,9 @@ public: { istream_loading = true; // NB: we need this flag for distinguish this operation in type's ctor... - const T* _elem; + T* elem; - U_NEW(T, _elem, T); + U_NEW(T, elem, T); streambuf* sb = is.rdbuf(); @@ -761,14 +883,14 @@ public: sb->sputbackc(c); - is >> *(T*)_elem; + is >> *elem; if (is.bad()) is.clear(); - else t.insert(key.rep, _elem); + else t.insert(key.rep, elem); } while (c != EOF); - u_destroy(_elem); + u_destroy(elem); istream_loading = false; } @@ -788,36 +910,24 @@ public: { U_TRACE(0+256, "UHashMap::operator<<(%p,%p)", &_os, &t) - U_INTERNAL_ASSERT(t.check_memory()) - U_INTERNAL_DUMP("t._length = %u", t._length) - UHashMapNode* _node; - UHashMapNode* _next; - UHashMapNode** ptr; - UHashMapNode** _end; - _os.put('['); _os.put('\n'); - for (_end = (ptr = t.table) + t._capacity; ptr < _end; ++ptr) + for (uint32_t idx = 0; idx < t._capacity; ++idx) { - if (*ptr) + if ((t.info[idx] & U_IS_BUCKET_TAKEN_MASK) != 0) { - _node = *ptr; + t.setNodePointer(idx); - do { - _node->key->write(_os); + t.node->key->write(_os); - _os.put('\t'); + _os.put('\t'); - _os << *((T*)_node->elem); + _os << *(T*)(t.node->elem); - _os.put('\n'); - - _next = _node->next; - } - while ((_node = _next)); + _os.put('\n'); } } @@ -833,33 +943,28 @@ public: private: U_DISALLOW_COPY_AND_ASSIGN(UHashMap) - - friend class UHTTP; - friend class UValue; - friend class WeightWord; - friend class UNoCatPlugIn; }; #if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX11) template class UHashMapAnonIter { public: - explicit UHashMapAnonIter(UHashMap* map, uint32_t length) : _length(length), _map(map) {} + explicit UHashMapAnonIter(UHashMap* m, uint32_t l) : map(m), length(l) {} - bool operator!=(const UHashMapAnonIter& other) const { return (_length != other._length); } + bool operator!=(const UHashMapAnonIter& other) const { return (length != other.length); } - UHashMapNode* operator*() const { return _node; } + UHashMapNode* operator*() const { return node; } UHashMapAnonIter& operator++() { - _node = (_length++ ? _map->next(_node): _map->first()); + node = (length++ ? map->nextNode() : map->firstNode()); return *this; } protected: - uint32_t _length; - UHashMap* _map; - UHashMapNode* _node; + UHashMap* map; + UHashMapNode* node; + uint32_t length; }; #endif @@ -871,9 +976,9 @@ public: U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%b", n, ignore_case) } - explicit UHashMap(uint32_t n = 64, bPFptpcu _set_index = setIndex) : UHashMap(n, _set_index) + explicit UHashMap(uint32_t n = 64, bPFpt fset_index = setIndex) : UHashMap(n, fset_index) { - U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%p", n, _set_index) + U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%p", n, fset_index) } ~UHashMap() @@ -881,6 +986,13 @@ public: U_TRACE_UNREGISTER_OBJECT(0, UHashMap) } + void insertAfterFind(const UString& str) + { + U_TRACE(0, "UHashMap::insertAfterFind(%V)", str.rep) + + UHashMap::insertAfterFind(str.rep); + } + void replaceAfterFind(const UString& str) { U_TRACE(0, "UHashMap::replaceAfterFind(%V)", str.rep) @@ -888,27 +1000,40 @@ public: UHashMap::replaceAfterFind(str.rep); } - void insert(const UStringRep* _key, const UStringRep* _elem) + void insert(const UStringRep* k, const UStringRep* e) { - U_TRACE(0, "UHashMap::insert(%V,%V)", _key, _elem) + U_TRACE(0, "UHashMap::insert(%V,%V)", k, e) - UHashMap::insert(_key, _elem); + UHashMap::insert(k, e); } - void insert(const UString& _key, const UString& str) + void insert(const UString& k, const UString& str) { - U_TRACE(0, "UHashMap::insert(%V,%V)", _key.rep, str.rep) + U_TRACE(0, "UHashMap::insert(%V,%V)", k.rep, str.rep) - UHashMap::insert(_key.rep, str.rep); + UHashMap::insert(k.rep, str.rep); } - UString erase(const UString& key); - - void insertAfterFind(const UString& _key, const UString& str) + UString erase(const UString& k) { - U_TRACE(0, "UHashMap::insertAfterFind(%V,%V)", _key.rep, str.rep) + U_TRACE(0, "UHashMap::erase(%V)", k.rep) - UHashMap::insertAfterFind(_key, str.rep); + if (UHashMap::lookup(k)) + { + UString str(elem()); + + U_INTERNAL_DUMP("str.reference() = %u", str.reference()) + + U_INTERNAL_ASSERT_MAJOR(str.reference(), 0) + + UHashMap::eraseAfterFind(); + + U_INTERNAL_DUMP("str.reference() = %u", str.reference()) + + U_RETURN_STRING(str); + } + + return UString::getStringNull(); } uint32_t getSpaceToDump() const __pure; @@ -920,9 +1045,21 @@ public: // OPERATOR [] - UString operator[](const char* _key); - UString operator[](const UString& _key) { return at(_key.rep); } - UString operator[](const UStringRep* _key) { return at(_key); } + UString at(const UString& k) { return (lkey = k.rep, at()); } + UString at(const UStringRep* k) { return (lkey = k, at()); } + UString at(const char* k, uint32_t klen) { return (setKey(k, klen), at()); } + + UString operator[](const char* k) + { + U_TRACE(0, "UHashMap::operator[](%S)", k) + + setKey(k, u__strlen(k, __PRETTY_FUNCTION__)); + + return at(); + } + + UString operator[](const UString& k) { return (lkey = k.rep, at()); } + UString operator[](const UStringRep* k) { return (lkey = k, at()); } // STREAMS @@ -931,24 +1068,28 @@ public: friend U_EXPORT ostream& operator<<(ostream& os, const UHashMap& t) { return operator<<(os, (const UHashMap&)t); } #endif + uint32_t loadFromData(const char* start, uint32_t size); + void loadFromData(const UString& str) { (void) loadFromData(U_STRING_TO_PARAM(str)); } protected: - UString at(const UStringRep* keyr); - UString at(const char* _key, uint32_t keylen); - uint32_t loadFromData(const char* start, uint32_t size); + UString at() + { + U_TRACE_NO_PARAM(0, "UHashMap::at()") + + if (UHashMap::lookup()) + { + UString str(elem()); + + U_RETURN_STRING(str); + } + + return UString::getStringNull(); + } private: U_DISALLOW_COPY_AND_ASSIGN(UHashMap) - - friend class UHTTP; - friend class UHTTP2; - friend class UFileConfig; - friend class UMimeHeader; - friend class UNoCatPlugIn; - - template friend class URDBObjectHandler; }; template <> class U_EXPORT UHashMap : public UHashMap { @@ -959,9 +1100,9 @@ public: U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%b", n, ignore_case) } - explicit UHashMap(uint32_t n = 64, bPFptpcu _set_index = setIndex) : UHashMap(n, _set_index) + explicit UHashMap(uint32_t n = 64, bPFpt fset_index = setIndex) : UHashMap(n, fset_index) { - U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%p", n, _set_index) + U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%p", n, fset_index) } ~UHashMap() @@ -969,11 +1110,44 @@ public: U_TRACE_UNREGISTER_OBJECT(0, UHashMap) } - bool empty(); + bool empty() + { + U_TRACE_NO_PARAM(0, "UHashMap::empty()") - void erase(const UString& _key, uint32_t pos); // remove element at pos + if (first()) + { + do { + pvec = elem(); + + if (pvec->empty() == false) U_RETURN(false); + } + while (next()); + } - void push(const UString& _key, const UString& str); + U_RETURN(true); + } + + void erase(const UString& k, uint32_t pos) // remove element at pos + { + U_TRACE(0, "UHashMap::erase(%V,%u)", k.rep, pos) + + if (UHashMap::lookup(k)) ((UVector*)node->elem)->erase(pos); + } + + void push(const UString& k, const UString& str) + { + U_TRACE(0, "UHashMap::push(%V,%V)", k.rep, str.rep) + + if (UHashMap::lookup(k)) pvec = (UVector*) node->elem; + else + { + U_NEW(UVector, pvec, UVector); + + UHashMap::insertAfterFind(pvec); + } + + pvec->push(str); + } private: U_DISALLOW_COPY_AND_ASSIGN(UHashMap) diff --git a/include/ulib/container/vector.h b/include/ulib/container/vector.h index 0887ae2d..ea8f6463 100644 --- a/include/ulib/container/vector.h +++ b/include/ulib/container/vector.h @@ -39,6 +39,8 @@ template class UVector; template class UOrmTypeHandler; template class UJsonTypeHandler; +typedef UVector UVectorUString; + //#define U_RING_BUFFER template <> class U_EXPORT UVector { @@ -1181,9 +1183,22 @@ public: uint32_t find( const char* s, uint32_t n) __pure; uint32_t findRange(const char* s, uint32_t n, uint32_t start, uint32_t end) __pure; - // Check equality with string at pos + // check equality with string at pos - bool isEqual(uint32_t pos, const UString& str, bool ignore_case = false) __pure; + __pure bool isEqual(uint32_t pos, const UString& str, bool ignore_case = false) + { + U_TRACE(0, "UVector::isEqual(%u,%V,%b)", pos, str.rep, ignore_case) + + U_CHECK_MEMORY + + if (_length && + UStringRep::equal_lookup(UVector::at(pos), str.rep, ignore_case)) + { + U_RETURN(true); + } + + U_RETURN(false); + } // Check equality with an existing vector object diff --git a/include/ulib/db/cdb.h b/include/ulib/db/cdb.h index 6777198f..23414bda 100644 --- a/include/ulib/db/cdb.h +++ b/include/ulib/db/cdb.h @@ -310,6 +310,8 @@ protected: // Save memory hash table as Constant DataBase + static bool writeTo(UStringRep* key, void* elem); // callWithDeleteForAllEntry()... + static bool writeTo(UCDB& cdb, UHashMap* table, uint32_t tbl_space, pvPFpvpb f = U_NULLPTR); // FOR RDB diff --git a/include/ulib/file.h b/include/ulib/file.h index b8024ea2..2b15dff8 100644 --- a/include/ulib/file.h +++ b/include/ulib/file.h @@ -17,7 +17,7 @@ #include #ifdef _MSWINDOWS_ -#define st_ino u_inode +# define st_ino u_inode #elif defined(HAVE_ASM_MMAN_H) # include #endif @@ -82,41 +82,53 @@ public: static void dec_num_file_object(int fd); static void chk_num_file_object(); #else -# define inc_num_file_object(pthis) -# define dec_num_file_object(fd) -# define chk_num_file_object() + # define inc_num_file_object(pthis) + # define dec_num_file_object(fd) + # define chk_num_file_object() #endif void reset() { U_TRACE_NO_PARAM(0, "UFile::reset()") - fd = -1; - map = (char*)MAP_FAILED; - st_size = 0; + st_size = map_size = 0; + map = (char*)MAP_FAILED; + fd = -1; } UFile() { U_TRACE_REGISTER_OBJECT(0, UFile, "", 0) - fd = -1; - map = (char*)MAP_FAILED; - path_relativ = U_NULLPTR; + reset(); - path_relativ_len = map_size = 0; + path_relativ_len = 0; + path_relativ = U_NULLPTR; inc_num_file_object(this); } - UFile(const UString& path, const UString* environment = U_NULLPTR) : pathname(path) + UFile(const UString& path) : pathname(path) + { + U_TRACE_REGISTER_OBJECT(0, UFile, "%V", path.rep) + + reset(); + + setPathRelativ(); + + inc_num_file_object(this); + } + + UFile(const UString& path, const UString* environment) : pathname(path) { U_TRACE_REGISTER_OBJECT(0, UFile, "%V,%p", path.rep, environment) - inc_num_file_object(this); + reset(); setPathRelativ(environment); + + inc_num_file_object(this); } #ifdef U_COVERITY_FALSE_POSITIVE @@ -131,11 +143,39 @@ public: // PATH - void setRoot(); - void setPath(const UString& path, const UString* environment = U_NULLPTR) + void setRoot() + { + U_TRACE_NO_PARAM(0, "UFile::setRoot()") + + reset(); + + pathname.setConstant(U_CONSTANT_TO_PARAM("/")); + + st_mode = S_IFDIR|0755; + path_relativ = pathname.data(); + path_relativ_len = 1; + + U_INTERNAL_DUMP("u_cwd(%u) = %S", u_cwd_len, u_cwd) + U_INTERNAL_DUMP("path_relativ(%u) = %.*S", path_relativ_len, path_relativ_len, path_relativ) + } + + void setPath(const UString& path) + { + U_TRACE(0, "UFile::setPath(%V)", path.rep) + + reset(); + + pathname = path; + + setPathRelativ(); + } + + void setPath(const UString& path, const UString* environment) { U_TRACE(0, "UFile::setPath(%V,%p)", path.rep, environment) + reset(); + pathname = path; setPathRelativ(environment); @@ -206,24 +246,33 @@ public: // OPEN - CLOSE - static int open(const char* _pathname, int flags, mode_t mode); - static int creat(const char* _pathname, int flags = O_TRUNC | O_RDWR, mode_t mode = PERM_FILE) + static int open(const char* pathname, int flags, mode_t mode) { - U_TRACE(0, "UFile::creat(%S,%d,%d)", _pathname, flags, mode) + U_TRACE(1, "UFile::open(%S,%d,%d)", pathname, flags, mode) - return open(_pathname, O_CREAT | flags, mode); + U_INTERNAL_ASSERT_POINTER(pathname) + U_INTERNAL_ASSERT_MAJOR(u__strlen(pathname, __PRETTY_FUNCTION__), 0) + + return U_SYSCALL(open, "%S,%d,%d", U_PATH_CONV(pathname), flags | O_CLOEXEC | O_BINARY, mode); // NB: we centralize here O_BINARY... } - static void close(int _fd) + static int creat(const char* pathname, int flags = O_TRUNC | O_RDWR, mode_t mode = PERM_FILE) { - U_TRACE(1, "UFile::close(%d)", _fd) + U_TRACE(0, "UFile::creat(%S,%d,%d)", pathname, flags, mode) - U_INTERNAL_ASSERT_DIFFERS(_fd, -1) + return open(pathname, O_CREAT | flags, mode); + } + + static void close(int fd) + { + U_TRACE(1, "UFile::close(%d)", fd) + + U_INTERNAL_ASSERT_DIFFERS(fd, -1) # ifdef U_COVERITY_FALSE_POSITIVE - if (_fd > 0) + if (fd > 0) # endif - (void) U_SYSCALL(close, "%d", _fd); + (void) U_SYSCALL(close, "%d", fd); } bool open( int flags = O_RDONLY); @@ -765,7 +814,30 @@ public: UString _getContent(bool bsize = true, bool brdonly = false, bool bmap = false); static UString contentOf(const UString& pathname, const UString& pinclude); - static UString contentOf(const UString& pathname, int flags = O_RDONLY, bool bstat = false, const UString* environment = U_NULLPTR); + + static UString contentOf(const UString& pathname, int flags = O_RDONLY, bool bstat = false) + { + U_TRACE(0, "UFile::contentOf(%V,%d,%b)", pathname.rep, flags, bstat) + + UFile file(pathname); + + if (file.open(flags)) return file.getContent((((flags & O_RDWR) | (flags & O_WRONLY)) == 0), bstat); + + return UString::getStringNull(); + } + + static UString contentOf(const UString& pathname, int flags, bool bstat, const UString* environment) + { + U_TRACE(0, "UFile::contentOf(%V,%d,%b,%p)", pathname.rep, flags, bstat, environment) + + U_INTERNAL_ASSERT(pathname) + + UFile file(pathname, environment); + + if (file.open(flags)) return file.getContent((((flags & O_RDWR) | (flags & O_WRONLY)) == 0), bstat); + + return UString::getStringNull(); + } static char* mmap(uint32_t* plength, int _fd = -1, int prot = PROT_READ | PROT_WRITE, int flags = MAP_SHARED | MAP_ANONYMOUS, uint32_t offset = 0); @@ -1074,7 +1146,7 @@ protected: uint32_t path_relativ_len, map_size; // size to mmap(), may be larger than the size of the file... UString pathname; char* map; - const char* path_relativ; // the string can be not writeable... + const char* path_relativ; // the string can be not writeable... int fd; static char* cwd_save; @@ -1086,7 +1158,28 @@ protected: void substitute(UFile& file); bool creatForWrite(int flags, bool bmkdirs); - void setPathRelativ(const UString* environment = U_NULLPTR); + void setPathRelativ(const UString* environment); + + void setPathRelativ() + { + U_TRACE_NO_PARAM(0, "UFile::setPathRelativ()") + + U_CHECK_MEMORY + + U_INTERNAL_ASSERT(pathname) + + // NB: the string can be not writable... + + path_relativ_len = pathname.size(); + path_relativ = u_getPathRelativ((pathname.isNullTerminated() ? pathname.data() : pathname.c_str()), &path_relativ_len); + + U_INTERNAL_ASSERT_MAJOR(path_relativ_len, 0) + + U_INTERNAL_DUMP("u_cwd(%u) = %S", u_cwd_len, u_cwd) + U_INTERNAL_DUMP("pathname(%u) = %V", pathname.size(), pathname.rep) + U_INTERNAL_DUMP("path_relativ(%u) = %.*S", path_relativ_len, path_relativ_len, path_relativ) + } + void setPath(const UFile& file, char* buffer_path, const char* suffix, uint32_t len); static uint32_t getMmapSize(uint32_t length) diff --git a/include/ulib/json/value.h b/include/ulib/json/value.h index 17615791..79b2e648 100644 --- a/include/ulib/json/value.h +++ b/include/ulib/json/value.h @@ -1992,7 +1992,7 @@ public: uhashmap* pmap = (uhashmap*)pval; - if (pmap->first() == 0) (void) json.append(U_CONSTANT_TO_PARAM("{}")); + if (pmap->empty()) (void) json.append(U_CONSTANT_TO_PARAM("{}")); else { json.push_back('{'); @@ -2013,8 +2013,7 @@ public: uhashmap* pmap = (uhashmap*)pval; - if (pmap->first() == U_NULLPTR) UValue::o.ival = UValue::listToValue(U_OBJECT_VALUE, U_NULLPTR); - else + if (pmap->first()) { ++UValue::pos; @@ -2036,6 +2035,10 @@ public: UValue::o.ival = UValue::listToValue(U_OBJECT_VALUE, UValue::sd[UValue::pos--].tails); } + else + { + UValue::o.ival = UValue::listToValue(U_OBJECT_VALUE, U_NULLPTR); + } if (UValue::pos != -1) UValue::nextParser(); } @@ -2062,9 +2065,7 @@ public: U_INTERNAL_DUMP("pelement->pkey(%p) = %V", rep, rep) - ((uhashmap*)pval)->lookup(rep); - - ((uhashmap*)pval)->insertAfterFind(rep, pitem); + ((uhashmap*)pval)->insert(rep, pitem); pelement = pelement->next; } @@ -2090,8 +2091,7 @@ public: UHashMap* pmap = (UHashMap*)pval; - if (pmap->first() == U_NULLPTR) (void) json.append(U_CONSTANT_TO_PARAM("{}")); - else + if (pmap->first()) { json.push_back('{'); @@ -2099,6 +2099,10 @@ public: json.setLastChar('}'); } + else + { + (void) json.append(U_CONSTANT_TO_PARAM("{}")); + } U_INTERNAL_DUMP("json(%u) = %V", json.size(), json.rep) } @@ -2109,8 +2113,7 @@ public: UHashMap* pmap = (UHashMap*)pval; - if (pmap->first() == U_NULLPTR) UValue::o.ival = UValue::listToValue(U_OBJECT_VALUE, U_NULLPTR); - else + if (pmap->first()) { ++UValue::pos; @@ -2137,6 +2140,10 @@ public: UValue::o.ival = UValue::listToValue(U_OBJECT_VALUE, UValue::sd[UValue::pos--].tails); } + else + { + UValue::o.ival = UValue::listToValue(U_OBJECT_VALUE, U_NULLPTR); + } if (UValue::pos != -1) UValue::nextParser(); } @@ -2161,9 +2168,7 @@ public: U_INTERNAL_DUMP("pelement->pkey(%p) = %V", rep, rep) - ((UHashMap*)pval)->lookup(rep); - - ((uhashmapbase*)pval)->insertAfterFind(rep, item.rep); + ((uhashmapbase*)pval)->insert(rep, item.rep); pelement = pelement->next; } diff --git a/include/ulib/mime/header.h b/include/ulib/mime/header.h index 860c67ed..ec1b205a 100644 --- a/include/ulib/mime/header.h +++ b/include/ulib/mime/header.h @@ -127,7 +127,7 @@ public: U_TRACE(0, "UMimeHeader::setHeader(%V,%V)", key.rep, value.rep) if (containsHeader(key)) table.replaceAfterFind(value); - else table.insertAfterFind(key, value); + else table.insertAfterFind(value); } void setHeader(const char* key, uint32_t keylen, const UString& value) @@ -135,12 +135,7 @@ public: U_TRACE(0, "UMimeHeader::setHeader(%.*S,%u,%V)", keylen, key, keylen, value.rep) if (containsHeader(key, keylen)) table.replaceAfterFind(value); - else - { - UString x(key, keylen); - - table.insertAfterFind(x, value); - } + else table.insertAfterFind(value); } bool setHeaderIfAbsent(const char* key, uint32_t keylen, const UString& value) @@ -149,9 +144,7 @@ public: if (containsHeader(key, keylen) == false) { - UString x(key, keylen); - - table.insertAfterFind(x, value); + table.insertAfterFind(value); U_RETURN(true); } diff --git a/include/ulib/string.h b/include/ulib/string.h index bd674132..488eb83a 100644 --- a/include/ulib/string.h +++ b/include/ulib/string.h @@ -116,6 +116,7 @@ class UProxyPlugIn; class Application; class UServer_Base; class UHashMapNode; +class UHashTableNode; class UMongoDBClient; class URDBClient_Base; class UQuotedPrintable; @@ -124,8 +125,12 @@ class UREDISClient_Base; template class UVector; template class UHashMap; +template class UHashTable; template class UJsonTypeHandler; +typedef void (*vPFprpv)(UStringRep*,void*); +typedef bool (*bPFprpv)(UStringRep*,void*); + class U_EXPORT UStringRep { public: @@ -933,13 +938,15 @@ private: str = ptr; } - // Equal lookup use case + // equal lookup use case static bool equal_lookup(UStringRep* key1, const char* s2, uint32_t n2, bool ignore_case) { U_TRACE(0, "UStringRep::equal_lookup(%V,%.*S,%u,%b)", key1, n2, s2, n2, ignore_case) + U_INTERNAL_ASSERT_POINTER(s2) U_INTERNAL_ASSERT_MAJOR(n2, 0) + U_INTERNAL_ASSERT_POINTER(key1) const char* s1; uint32_t n1 = key1->size(); @@ -956,21 +963,25 @@ private: U_RETURN(false); } - static bool equal_lookup(const UStringRep* key1, const char* s1, uint32_t n1, const UStringRep* key2, uint32_t n2, bool ignore_case) + static bool equal_lookup(const UStringRep* key1, const UStringRep* key2, bool ignore_case) { - U_TRACE(0, "UStringRep::equal_lookup(%V,%.*S,%u,%V,%u,%b)", key1, n1, s1, n1, key2, n2, ignore_case) + U_TRACE(0, "UStringRep::equal_lookup(%V,%V,%b)", key1, key2, ignore_case) + + U_INTERNAL_ASSERT_POINTER(key1) + U_INTERNAL_ASSERT_POINTER(key2) + + const char* s1; + const char* s2; + uint32_t n1 = key1->size(), + n2 = key2->size(); U_INTERNAL_ASSERT_MAJOR(n1, 0) U_INTERNAL_ASSERT_MAJOR(n2, 0) - U_INTERNAL_ASSERT_EQUALS(key1->data(), s1) - U_INTERNAL_ASSERT_EQUALS(key1->size(), n1) - U_INTERNAL_ASSERT_EQUALS(key2->size(), n2) - const char* s2; - - if (n1 == n2 && + if ( n1 == n2 && (key1 == key2 || - (s2 = key2->data(), memcmp(s1, s2, n1) == 0) || + (s1 = key1->data(), + s2 = key2->data(), memcmp(s1, s2, n1) == 0) || (ignore_case && u__strncasecmp(s1, s2, n1) == 0))) { U_RETURN(true); @@ -1008,6 +1019,7 @@ private: friend class UProxyPlugIn; friend class UHashMapNode; friend class UServer_Base; + friend class UHashTableNode; friend class UMongoDBClient; friend class URDBClient_Base; friend class UQuotedPrintable; @@ -1017,6 +1029,7 @@ private: template friend class UVector; template friend class UHashMap; + template friend class UHashTable; template friend class UJsonTypeHandler; template friend void u_construct(const T*, uint32_t); }; @@ -1191,6 +1204,7 @@ public: } protected: + static UStringRep* pkey; static UString* string_null; friend class ULib; @@ -1203,6 +1217,7 @@ protected: template friend class UVector; template friend class UHashMap; + template friend class UHashTable; explicit UString(UStringRep** pr) : rep(*pr) // NB: for toUTF8() and fromUTF8()... { @@ -1750,10 +1765,7 @@ public: U_INTERNAL_ASSERT_MAJOR(rep->_length, 0) if (writeable()) rep->setNullTerminated(); - else - { - duplicate(); - } + else duplicate(); U_ASSERT_EQUALS(u__strlen(rep->str, __PRETTY_FUNCTION__), rep->_length) } diff --git a/include/ulib/utility/http2.h b/include/ulib/utility/http2.h index 4c536766..76c598ec 100644 --- a/include/ulib/utility/http2.h +++ b/include/ulib/utility/http2.h @@ -522,13 +522,13 @@ protected: static void wrapRequest(); #endif - static bool setIndexStaticTable(UHashMap* table, const char* key, uint32_t length) + static bool setIndexStaticTable(UHashMap* table) { - U_TRACE(0, "UHTTP2::setIndexStaticTable(%p,%.*S,%u)", table, length, key, length) + U_TRACE(0, "UHTTP2::setIndexStaticTable(%p)", table) - // if (bhash) table->hash = u_hash_ignore_case((unsigned char*)key, length); + // if (bhash) UHashMap::lhash = u_hash_ignore_case((unsigned char*)U_STRING_TO_PARAM(*UHashMap::lkey)); - UHashMap::_setIndex(table); + UHashMap::setIdx(table); U_RETURN(true); // NB: ignore case... } @@ -774,13 +774,9 @@ protected: { U_TRACE(0, "UHTTP2::findHeader(%u)", index) - UHashMap* table = &(pConnection->dtable); + UHashMap::lhash = hash_static_table[index]; - table->hash = hash_static_table[index]; - - table->lookup(hpack_static_table[index].name); - - if (table->node) U_RETURN(true); + if (pConnection->dtable.lookup(hpack_static_table[index].name)) U_RETURN(true); U_RETURN(false); } @@ -810,13 +806,11 @@ protected: * { * U_TRACE(0, "UHTTP2::eraseHeader(%u)", index) * + * UHashMap::lhash = hash_static_table[index]; + * * UHashMap* table = &(pConnection->itable); * - * table->hash = hash_static_table[index]; - * - * table->lookup(hpack_static_table[index].name); - * - * if (table->node) table->eraseAfterFind(); + * if (table->lookup(hpack_static_table[index].name)) table->eraseAfterFind(); * } * * static void decodeHeadersResponse(unsigned char* ptr, uint32_t length) diff --git a/include/ulib/utility/uhttp.h b/include/ulib/utility/uhttp.h index 480955ed..f9fedf74 100644 --- a/include/ulib/utility/uhttp.h +++ b/include/ulib/utility/uhttp.h @@ -1319,11 +1319,6 @@ private: static UString getHTMLDirectoryList() U_NO_EXPORT; -#ifdef DEBUG - static bool cache_file_check_memory(); - static bool check_memory(UStringRep* key, void* value) U_NO_EXPORT; -#endif - #if defined(U_ALIAS) && defined(USE_LIBPCRE) // REWRITE RULE static void processRewriteRule() U_NO_EXPORT; #endif diff --git a/src/ulib/base/utility.c b/src/ulib/base/utility.c index a5c46818..63ce8b68 100644 --- a/src/ulib/base/utility.c +++ b/src/ulib/base/utility.c @@ -306,6 +306,30 @@ __pure unsigned long u__atoi(const char* restrict s) return u__strtoul(ptr, s-ptr); } +__pure int8_t u_log2(uint64_t value) +{ + static int8_t table[64] = { + 63, 0, 58, 1, 59, 47, 53, 2, + 60, 39, 48, 27, 54, 33, 42, 3, + 61, 51, 37, 40, 49, 18, 28, 20, + 55, 30, 34, 11, 43, 14, 22, 4, + 62, 57, 46, 52, 38, 26, 32, 41, + 50, 36, 17, 19, 29, 10, 13, 21, + 56, 45, 25, 31, 35, 16, 9, 12, + 44, 24, 15, 8, 23, 7, 6, 5 }; + + U_INTERNAL_TRACE("u_log2(%llu)", value) + + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + value |= value >> 32; + + return table[((value - (value >> 1)) * 0x07EDD5E59A4E28C2) >> 58]; +} + /* To avoid libc locale overhead */ __pure int u__strncasecmp(const char* restrict s1, const char* restrict s2, size_t n) @@ -2659,7 +2683,7 @@ uint32_t u_get_num_random(uint32_t range) if (range) { - result = ((result % range) + 1); + result = (result % range)+1; U_INTERNAL_ASSERT(result <= range) } diff --git a/src/ulib/command.cpp b/src/ulib/command.cpp index 7fba9477..165e9ffe 100644 --- a/src/ulib/command.cpp +++ b/src/ulib/command.cpp @@ -103,9 +103,13 @@ void UCommand::setCommand() ncmd = u_splitCommand(U_STRING_TO_PARAM(command), argv, buffer, sizeof(buffer)); - U_INTERNAL_DUMP("ncmd = %d", ncmd) + U_INTERNAL_DUMP("ncmd = %u", ncmd) - if (ncmd != -1) + if (ncmd == U_NOT_FOUND) + { + U_WARNING("setCommand() failed, command %V not found", command.rep); + } + else { U_INTERNAL_ASSERT_RANGE(1,ncmd,U_MAX_ARGS) @@ -121,23 +125,19 @@ void UCommand::setCommand() U_MEMCPY(argv_exec, argv, n * sizeof(char*)); // NB: copy also null terminator... } - else - { - U_WARNING("setCommand() failed, command %V not found", command.rep); - } U_DUMP_ATTRS(argv_exec) } -int32_t UCommand::setEnvironment(const UString& env, char**& _envp) +uint32_t UCommand::setEnvironment(const UString& env, char**& _envp) { U_TRACE(0, "UCommand::setEnvironment(%V,%p)", env.rep, _envp) char* argp[U_MAX_ARGS]; - int32_t _nenv = u_split(U_STRING_TO_PARAM(env), argp, U_NULLPTR); + uint32_t _nenv = u_split(U_STRING_TO_PARAM(env), argp, U_NULLPTR); - U_INTERNAL_DUMP("_nenv = %d", _nenv) + U_INTERNAL_DUMP("_nenv = %u", _nenv) U_INTERNAL_ASSERT_RANGE(1, _nenv, U_MAX_ARGS) @@ -187,11 +187,11 @@ void UCommand::setFileArgument() U_INTERNAL_ASSERT_POINTER(argv_exec) - U_INTERNAL_DUMP("ncmd = %d", ncmd) + U_INTERNAL_DUMP("ncmd = %u", ncmd) - for (int32_t i = ncmd; i >= 2; --i) + for (uint32_t i = ncmd; i >= 2; --i) { - U_INTERNAL_DUMP("argv_exec[%d] = %S", i, argv_exec[i]) + U_INTERNAL_DUMP("argv_exec[%u] = %S", i, argv_exec[i]) if (u_get_unalignedp32(argv_exec[i]) == U_MULTICHAR_CONSTANT32('$','F','I','L')) { @@ -201,12 +201,12 @@ void UCommand::setFileArgument() } } - U_INTERNAL_DUMP("nfile = %d", nfile) + U_INTERNAL_DUMP("nfile = %u", nfile) } -void UCommand::setNumArgument(int32_t n, bool bfree) +void UCommand::setNumArgument(uint32_t n, bool bfree) { - U_TRACE(1, "UCommand::setNumArgument(%d,%b)", n, bfree) + U_TRACE(1, "UCommand::setNumArgument(%u,%b)", n, bfree) U_INTERNAL_ASSERT_POINTER(argv_exec) @@ -234,11 +234,10 @@ U_NO_EXPORT void UCommand::setStdInOutErr(int fd_stdin, bool flag_stdin, bool fl { if (fd_stdin == -1) { - UProcess::pipe(STDIN_FILENO); // UProcess::filedes[0] is for READING, + UProcess::pipe(STDIN_FILENO); // UProcess::filedes[0] is for READING // UProcess::filedes[1] is for WRITING # ifdef _MSWINDOWS_ - // Ensure the write handle to the pipe for STDIN is not inherited - (void) U_SYSCALL(SetHandleInformation, "%p,%ld,%ld", UProcess::hFile[1], HANDLE_FLAG_INHERIT, 0); + (void) U_SYSCALL(SetHandleInformation, "%p,%ld,%ld", UProcess::hFile[1], HANDLE_FLAG_INHERIT, 0); // Ensure the write handle to the pipe for STDIN is not inherited # endif } else @@ -249,18 +248,14 @@ U_NO_EXPORT void UCommand::setStdInOutErr(int fd_stdin, bool flag_stdin, bool fl if (flag_stdout) { - UProcess::pipe(STDOUT_FILENO); // UProcess::filedes[2] is for READING, + UProcess::pipe(STDOUT_FILENO); // UProcess::filedes[2] is for READING // UProcess::filedes[3] is for WRITING # ifdef _MSWINDOWS_ - // Ensure the read handle to the pipe for STDOUT is not inherited - (void) U_SYSCALL(SetHandleInformation, "%p,%ld,%ld", UProcess::hFile[2], HANDLE_FLAG_INHERIT, 0); + (void) U_SYSCALL(SetHandleInformation, "%p,%ld,%ld", UProcess::hFile[2], HANDLE_FLAG_INHERIT, 0); // Ensure the read handle to the pipe for STDOUT is not inherited # endif } - if (fd_stderr != -1) - { - UProcess::filedes[5] = fd_stderr; - } + if (fd_stderr != -1) UProcess::filedes[5] = fd_stderr; } U_NO_EXPORT void UCommand::execute(bool flag_stdin, bool flag_stdout, bool flag_stderr) @@ -272,7 +267,7 @@ U_NO_EXPORT void UCommand::execute(bool flag_stdin, bool flag_stdout, bool flag_ if (flag_expand != U_NOT_FOUND) { - // NB: it must remain in this way (I don't understand why...) + // NB: it must be in this way but I don't understand why environment = UStringExt::expandEnvironmentVar(environment, &environment); @@ -289,13 +284,13 @@ U_NO_EXPORT void UCommand::execute(bool flag_stdin, bool flag_stdout, bool flag_ U_INTERNAL_ASSERT_RANGE(begin, argv_exec[1], _end) # endif - int32_t i; + uint32_t i; - // NB: we cannot check argv a cause of addArgument()... + // NB: we cannot check argv cause of addArgument()... for (i = 0; argv_exec[1+i]; ++i) {} - U_INTERNAL_ASSERT_EQUALS(i,ncmd) + U_INTERNAL_ASSERT_EQUALS(i, ncmd) if (envp && envp != environ && @@ -337,7 +332,7 @@ U_NO_EXPORT bool UCommand::postCommand(UString* input, UString* output) { U_TRACE(1, "UCommand::postCommand(%p,%p)", input, output) - U_INTERNAL_DUMP("pid = %d", pid) + U_INTERNAL_DUMP("pid = %u", pid) if (input) { @@ -421,13 +416,13 @@ bool UCommand::setMsgError(const char* cmd, bool only_if_error) U_INTERNAL_ASSERT_EQUALS(u_buffer_len, 0) - U_INTERNAL_DUMP("pid = %d exit_value = %d status = %d", pid, exit_value, status) + U_INTERNAL_DUMP("pid = %u exit_value = %d status = %d", pid, exit_value, status) // NB: '<' is reserved for xml... if (isStarted() == false) { - u_buffer_len = u__snprintf(u_buffer, U_MAX_SIZE_PREALLOCATE, U_CONSTANT_TO_PARAM("command %S didn't start %R"), cmd, 0); // NB: the last argument (0) is necessary... + u_buffer_len = u__snprintf(u_buffer, U_BUFFER_SIZE, U_CONSTANT_TO_PARAM("command %S didn't start %R"), cmd, 0); // NB: the last argument (0) is necessary... U_RETURN(true); } @@ -435,7 +430,7 @@ bool UCommand::setMsgError(const char* cmd, bool only_if_error) if (isTimeout() && timeoutMS > 0) { - u_buffer_len = u__snprintf(u_buffer, U_MAX_SIZE_PREALLOCATE, U_CONSTANT_TO_PARAM("command %S (pid %u) excedeed time (%d secs) for execution"), cmd, pid, timeoutMS / 1000); + u_buffer_len = u__snprintf(u_buffer, U_BUFFER_SIZE, U_CONSTANT_TO_PARAM("command %S (pid %u) excedeed time (%u secs) for execution"), cmd, pid, timeoutMS / 1000); U_RETURN(true); } @@ -444,8 +439,8 @@ bool UCommand::setMsgError(const char* cmd, bool only_if_error) { char buffer[128]; - u_buffer_len = u__snprintf(u_buffer, U_MAX_SIZE_PREALLOCATE, U_CONSTANT_TO_PARAM("command %S started (pid %u) and ended with status: %d (%d, %s)"), - cmd, pid, status, exit_value, UProcess::exitInfo(buffer, status)); + u_buffer_len = u__snprintf(u_buffer, U_BUFFER_SIZE, U_CONSTANT_TO_PARAM("command %S started (pid %u) and ended with status: %d (%d, %s)"), + cmd, pid, status, exit_value, UProcess::exitInfo(buffer, status)); } U_RETURN(false); @@ -459,7 +454,7 @@ bool UCommand::executeWithFileArgument(UString* output, UFile* file) int fd_stdin = -1; - if (getNumFileArgument() == -1) + if (getNumFileArgument() == U_NOT_FOUND) { if (file->open()) fd_stdin = file->getFd(); } diff --git a/src/ulib/container/hash_map.cpp b/src/ulib/container/hash_map.cpp index c50aa766..470a3728 100644 --- a/src/ulib/container/hash_map.cpp +++ b/src/ulib/container/hash_map.cpp @@ -13,553 +13,353 @@ #include -bool UHashMap::istream_loading; -UStringRep* UHashMap::pkey; +bool UHashMap::istream_loading; +uint8_t UHashMap::linfo; +uint32_t UHashMap::lhash; +uint32_t UHashMap::index; +const void* UHashMap::lelem; +UHashMapNode* UHashMap::node; +const UStringRep* UHashMap::lkey; +UVector* UHashMap::pvec; -UHashMap::UHashMap(uint32_t n, bPFptpcu fset_index) +void UHashMap::_allocate(uint32_t n) { - U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%p", n, fset_index) - - set_index = fset_index; - - init(n); -} - -UHashMap::UHashMap(uint32_t n, bool ignore_case) -{ - U_TRACE_REGISTER_OBJECT(0, UHashMap, "%u,%b", n, ignore_case) - - set_index = (ignore_case ? setIndexIgnoreCase : setIndex); - - init(n); -} - -void UHashMap::allocate(uint32_t n) -{ - U_TRACE(0, "UHashMap::allocate(%u)", n) + U_TRACE(0, "UHashMap::_allocate(%u)", n) U_CHECK_MEMORY - U_INTERNAL_ASSERT_EQUALS(n & 1, 0) + // must be a power of 2, It's done this way because bitwise-and is an inexpensive operation, whereas integer modulo (%) is quite heavy - if (_capacity) _deallocate(); + U_INTERNAL_ASSERT_EQUALS(n & (n-1), 0) - _allocate(n); + info = (uint8_t*) UMemoryPool::_malloc(n, 1+UHashMapNode::size(), false); + table = (char*) (info + n); + + (void) U_SYSCALL(memset, "%p,%d,%u", info, 0, n); + + mask = (_capacity = n) - 1; + + U_INTERNAL_ASSERT_EQUALS(_capacity & mask, 0) + + max_num_num_elements_allowed = U_min(_capacity-2, (uint32_t)(_capacity * U_MAX_LOAD_FACTOR)); // max * (1 - 1/20) = max * 0.95 + + U_INTERNAL_DUMP("_capacity = %u mask = %u max_num_num_elements_allowed = %u", _capacity, mask, max_num_num_elements_allowed) } -void UHashMap::lookup(const UStringRep* keyr) +bool UHashMap::lookup() { - U_TRACE(0, "UHashMap::lookup(%V)", keyr) + U_TRACE(0, "UHashMap::lookup()") U_CHECK_MEMORY U_INTERNAL_ASSERT_POINTER(set_index) U_INTERNAL_ASSERT_MAJOR(_capacity, 0) - const UStringRep* keyn; - uint32_t sz1 = keyr->size(); - const char* ptr1 = keyr->data(); + bool ignore_case = set_index(this); - bool ignore_case = set_index(this, ptr1, sz1); - - U_INTERNAL_DUMP("index = %u ignore_case = %b", index, ignore_case) + U_INTERNAL_DUMP("lhash = %u index = %u ignore_case = %b", lhash, index, ignore_case) U_INTERNAL_ASSERT_MINOR(index, _capacity) - for (node = table[index]; node; node = node->next) - { - U_INTERNAL_ASSERT_POINTER(node->key) - - uint32_t sz2 = (keyn = node->key)->size(); - - U_INTERNAL_DUMP("node->key(%u) = %p %V", sz2, keyn, keyn) - - U_INTERNAL_ASSERT_MAJOR(sz2, 0) - - if (UStringRep::equal_lookup(keyr, ptr1, sz1, keyn, sz2, ignore_case)) - { - U_INTERNAL_DUMP("node = %p", node) - - return; - } - } -} - -void* UHashMap::erase(const UStringRep* _key) -{ - U_TRACE(0, "UHashMap::erase(%V)", _key) - - lookup(_key); - - if (node) - { - const void* _elem = node->elem; - - eraseAfterFind(); - - U_RETURN((void*)_elem); - } - - U_RETURN((void*)U_NULLPTR); -} - -void UHashMap::insertAfterFind(const UStringRep* _key, const void* _elem) -{ - U_TRACE(0, "UHashMap::insertAfterFind(%V,%p)", _key, _elem) - - U_CHECK_MEMORY - - U_INTERNAL_ASSERT_DIFFERS(_key, pkey) - U_INTERNAL_ASSERT_EQUALS(node, U_NULLPTR) - - U_INTERNAL_DUMP("index = %u", index) - /** - * list self-organizing (move-to-front), we place before - * the element at the beginning of the list of collisions + * Robin Hood Hashing uses the hash value to calculate the position to place it, than does linear probing until it finds an empty spot to place it. + * While doing so it swaps out entries that have a lesser distance to its original bucket. This minimizes the maximum time a lookup takes. For a lookup, + * it is only necessary to lineary probe until the distance to the original bucket is larger than the current element’s distance. + * + * In this “Infobyte” implementation variant, instead of storing the full 64 bit hash value I directly store the distance to the original bucket in a byte. + * One bit of this byte is used to mark the bucket as taken or empty. The bit layout is defined like this: + * + * bits: | 7 | 6 5 4 3 2 1 0| + * | ^ | offset | + * | + * full? */ - U_NEW(UHashMapNode, table[index], UHashMapNode(_key, _elem, table[index], hash)); + linfo = U_IS_BUCKET_TAKEN_MASK; - node = table[index]; - - ++_length; - - U_INTERNAL_DUMP("_length = %u", _length) -} - -void UHashMap::_eraseAfterFind() -{ - U_TRACE_NO_PARAM(0, "UHashMap::_eraseAfterFind()") - - U_CHECK_MEMORY - - U_INTERNAL_DUMP("node = %p", node) - - UHashMapNode* prev = U_NULLPTR; - - for (UHashMapNode* pnode = table[index]; pnode; pnode = pnode->next) + while (linfo < info[index]) { - if (pnode == node) - { - /** - * list self-organizing (move-to-front), we place before - * the element at the beginning of the list of collisions - */ + U_INTERNAL_DUMP("linfo = %u info[%u] = %u", linfo, index, info[index]) - if (prev) - { - prev->next = pnode->next; - pnode->next = table[index]; - table[index] = pnode; - } + index = (index+1) & mask; - U_INTERNAL_ASSERT_EQUALS(node,table[index]) - - break; - } - - prev = pnode; + ++linfo; } - U_INTERNAL_DUMP("prev = %p", prev) + // check while info matches with the source index - /** - * list self-organizing (move-to-front), we requires the - * item to be deleted at the beginning of the list of collisions - */ - - U_INTERNAL_ASSERT_EQUALS(node, table[index]) - - table[index] = node->next; -} - -void UHashMap::eraseAfterFind() -{ - U_TRACE_NO_PARAM(0, "UHashMap::eraseAfterFind()") - - _eraseAfterFind(); - - delete node; - - --_length; - - U_INTERNAL_DUMP("_length = %u", _length) -} - -void UHashMap::replaceKey(const UString& _key) -{ - U_TRACE(0, "UHashMap::replaceKey(%V)", _key.rep) - - UHashMapNode* pnode = node; - - _eraseAfterFind(); - - lookup(_key); - - U_INTERNAL_ASSERT_EQUALS(node, U_NULLPTR) - - pnode->hash = hash; - pnode->next = table[index]; - - ((UStringRep*)pnode->key)->release(); // NB: we decreases the reference string... - - pnode->key = _key.rep; - - ((UStringRep*)pnode->key)->hold(); // NB: we increases the reference string... - - /** - * list self-organizing (move-to-front), we place before - * the element at the beginning of the list of collisions - */ - - node = table[index] = pnode; -} - -void UHashMap::reserve(uint32_t n) -{ - U_TRACE(0, "UHashMap::reserve(%u)", n) - - U_INTERNAL_ASSERT_MAJOR(_capacity, 1) - - uint32_t new_capacity = n << 1; // x 2... - - if (new_capacity == _capacity) return; - - UHashMapNode** old_table = table; - uint32_t old_capacity = _capacity, i; - - _allocate(new_capacity); - -#ifdef DEBUG - int sum = 0, max = 0, min = 1024, width; -#endif - - // we insert the old elements - - UHashMapNode* _next; - - for (i = 0; i < old_capacity; ++i) + while (linfo == info[index]) { - if (old_table[i]) - { - node = old_table[i]; + setNodePointer(); -# ifdef DEBUG - ++sum; - width = -1; -# endif + if (UStringRep::equal_lookup(lkey, node->key, ignore_case)) U_RETURN(true); - do { -# ifdef DEBUG - ++width; -# endif + index = (index+1) & mask; - _next = node->next; - index = node->hash % _capacity; - - U_INTERNAL_DUMP("i = %u index = %u hash = %u", i, index, node->hash) - - /** - * list self-organizing (move-to-front), we place before - * the element at the beginning of the list of collisions - */ - - node->next = table[index]; - table[index] = node; - } - while ((node = _next)); - -# ifdef DEBUG - if (max < width) max = width; - if (min > width) min = width; -# endif - } + ++linfo; } - UMemoryPool::_free(old_table, old_capacity, sizeof(UHashMapNode*)); + U_INTERNAL_DUMP("info[%u] = %u linfo = %u", index, info[index], linfo) - U_INTERNAL_DUMP("OLD: collision(min,max) = (%3d,%3d) - distribution = %3f", min, max, (sum ? (double)_length / (double)sum : 0)) + // nothing found! -#ifdef DEBUG - sum = 0, max = 0, min = 1024; - - UHashMapNode* _n; - - for (i = 0; i < _capacity; ++i) - { - if (table[i]) - { - _n = table[i]; - - ++sum; - width = -1; - - do { - ++width; - - _next = _n->next; - } - while ((_n = _next)); - - if (max < width) max = width; - if (min > width) min = width; - } - } -#endif - - U_INTERNAL_DUMP("NEW: collision(min,max) = (%3d,%3d) - distribution = %3f", min, max, (sum ? (double)_length / (double)sum : 0)) + U_RETURN(false); } +#define U_HASHMAP_SAVE_CONTEXT \ + uint8_t _tmp1 = linfo; \ + uint32_t _tmp2 = index; \ + uint32_t _tmp3 = lhash; \ + const void* _tmp4 = lelem; \ + const UStringRep* _tmp5 = lkey + +#define U_HASHMAP_RESTORE_CONTEXT \ + linfo = _tmp1; \ + index = _tmp2; \ + lhash = _tmp3; \ + lelem = _tmp4; \ + lkey = _tmp5 + #ifdef DEBUG -bool UHashMap::check_memory() const // check all element +bool UHashMap::checkAt(const UStringRep* k, const void* e) { - U_TRACE_NO_PARAM(0+256, "UHashMap::check_memory()") + U_TRACE(0, "UHashMap::checkAt(%V,%p)", k, e) - U_CHECK_MEMORY + U_HASHMAP_SAVE_CONTEXT; - U_INTERNAL_DUMP("_length = %u", _length) + bool result = (at(k) == e); - if (_length) + U_HASHMAP_RESTORE_CONTEXT; + + U_RETURN(result); +} + +bool UHashMap::invariant() +{ + U_TRACE_NO_PARAM(0, "UHashMap::invariant()") + + for (uint32_t idx = 0; idx < _capacity; ++idx) { - const void* pelem; - UHashMapNode* pnode; - UHashMapNode* pnext; - int sum = 0, max = 0, min = 1024, width; - - for (uint32_t _index = 0; _index < _capacity; ++_index) + if ((info[idx] & U_IS_BUCKET_TAKEN_MASK) != 0) { - pnode = table[_index]; + setNodePointer(idx); - if (pnode == U_NULLPTR) continue; - - ++sum; - width = 0; - - U_INTERNAL_DUMP("_index = %u sum = %u", _index, sum) - -loop: U_INTERNAL_ASSERT_POINTER(pnode) - - U_INTERNAL_DUMP("pnode->key(%u) = %p %V", pnode->key->size(), pnode->key, pnode->key) - - U_INTERNAL_ASSERT_MAJOR(pnode->key->size(), 0) - - pelem = pnode->elem; - - U_INTERNAL_DUMP("pelem = %p width = %u", pelem, width) - - U_INTERNAL_ASSERT_EQUALS(((const UMemoryError*)pelem)->_this, (void*)U_CHECK_MEMORY_SENTINEL) - - if (pnode->next) - { - pnext = pnode->next; - - U_INTERNAL_DUMP("pnode = %p pnext = %p", pnode, pnext) - - U_INTERNAL_ASSERT_POINTER(pnext) - U_INTERNAL_ASSERT_DIFFERS(pnode, pnext) - - ++width; - - pnode = pnext; - - goto loop; - } - - if (max < width) max = width; - if (min > width) min = width; + if (checkAt(node->key, node->elem) == false) U_RETURN(false); } - - U_INTERNAL_DUMP("collision(min,max) = (%d,%d) - distribution = %f", min, max, (sum ? (double)_length / (double)sum : 0)) } U_RETURN(true); } #endif -UHashMapNode* UHashMap::first() +#define U_HASHMAP_SWAP_NODE(e,k,h) \ + const void* _tmp1 = node->elem; \ + node->elem = e; \ + e = _tmp1; \ + const UStringRep* _tmp2 = node->key; \ + node->key = k; \ + k = _tmp2; \ + uint32_t _tmp3 = node->hash; \ + node->hash = h; \ + h = _tmp3 + +void UHashMap::swapNodeInResize() { - U_TRACE_NO_PARAM(0, "UHashMap::first()") + U_TRACE_NO_PARAM(0, "UHashMap::swapNodeInResize()") + + swapInfo(); + + UHashMapNode* pnode = node; + + U_INTERNAL_ASSERT_POINTER(pnode) + + setNodePointer(); + + U_HASHMAP_SWAP_NODE(pnode->elem, pnode->key, pnode->hash); + + U_ASSERT(checkAt(node->key, node->elem)) + + node = pnode; +} + +void UHashMap::increase_size() +{ + U_TRACE(0, "UHashMap::increase_size()") + + char* old_table = table; + uint8_t* old_info = info; + uint32_t old_capacity = _capacity; + + U_INTERNAL_ASSERT_MAJOR(_capacity, 1) + + _allocate(_capacity << 1); // x 2... + + // we insert the old elements + + for (uint32_t idx = 0; idx < old_capacity; ++idx) + { + if ((old_info[idx] & U_IS_BUCKET_TAKEN_MASK) != 0) // inserts a keyval that is guaranteed to be new, e.g. when the hashmap is resized + { + setNodePointer(old_table, idx); + + index = node->hash & mask; + + linfo = U_IS_BUCKET_TAKEN_MASK; + + while (linfo <= info[index]) // skip forward. Use <= because we know the element is not there + { + U_INTERNAL_DUMP("linfo = %u info[%u] = %u", linfo, index, info[index]) + + index = (index+1) & mask; + + ++linfo; + } + + // loop while we have not found an empty spot + + while ((info[index] & U_IS_BUCKET_TAKEN_MASK) != 0) + { + U_INTERNAL_ASSERT_DIFFERS(linfo, 0) // Overflow! This is bad, shouldn't happen + + if (linfo > info[index]) swapNodeInResize(); + + index = (index+1) & mask; + + ++linfo; + } + + // bucket is empty! put it there + + lelem = node->elem; + lkey = node->key; + lhash = node->hash; + + putNode(); + } + } + + UMemoryPool::_free(old_info, old_capacity, 1+UHashMapNode::size()); +} + +void UHashMap::swapNode() +{ + U_TRACE_NO_PARAM(0, "UHashMap::swapNode()") + + swapInfo(); + + setNodePointer(); + + U_INTERNAL_DUMP("lkey = %V lelem = %p lhash = %u node->key = %V node->elem = %p node->hash = %u", lkey, lelem, lhash, node->key, node->elem, node->hash) + + U_HASHMAP_SWAP_NODE(lelem, lkey, lhash); + + U_INTERNAL_DUMP("lkey = %V lelem = %p lhash = %u node->key = %V node->elem = %p node->hash = %u", lkey, lelem, lhash, node->key, node->elem, node->hash) + + U_ASSERT(checkAt(node->key, node->elem)) +} + +void UHashMap::insertAfterFind() +{ + U_TRACE_NO_PARAM(0, "UHashMap::insertAfterFind()") + + U_CHECK_MEMORY + + U_INTERNAL_DUMP("_length = %u max_num_num_elements_allowed = %u", _length, max_num_num_elements_allowed) + + U_INTERNAL_ASSERT_MINOR(_length, max_num_num_elements_allowed) + + U_INTERNAL_DUMP("info[%u] = %u linfo = %u", index, info[index], linfo) + + /** + * Robin Hood Hashing uses the hash value to calculate the position to place it, than does linear probing until it finds an empty spot to place it. + * While doing so it swaps out entries that have a lesser distance to its original bucket. This minimizes the maximum time a lookup takes. For a lookup, + * it is only necessary to lineary probe until the distance to the original bucket is larger than the current element’s distance + */ + +loop: + while (info[index] >= U_IS_BUCKET_TAKEN_MASK && linfo) // loop while we have not found an empty spot, and while no info overflow + { + U_INTERNAL_DUMP("linfo = %u info[%u] = %u", linfo, index, info[index]) + + if (linfo > info[index]) swapNode(); + + index = (index+1) & mask; + + ++linfo; + } + + if (linfo) putNode(); // bucket is empty! put it there + else + { + // Overflow: resize and try again + + const void* tmp1 = lelem; + const UStringRep* tmp2 = lkey; + + increase_size(); + + lelem = tmp1; + lkey = tmp2; + + (void) lookup(); + + goto loop; + } + + if (++_length == max_num_num_elements_allowed) increase_size(); +} + +void UHashMap::eraseAfterFind() +{ + U_TRACE_NO_PARAM(0, "UHashMap::eraseAfterFind()") + + U_CHECK_MEMORY + + node->reset(); + + // perform backward shift deletion: shift elements to the left until we find one that is either empty or has zero offset + // + // NB: no need to check for last element, this acts as a sentinel + + uint32_t nextIdx = (index+1) & mask; + + U_INTERNAL_DUMP("index = %u nextIdx = %u", index, nextIdx) + + while (info[nextIdx] > U_IS_BUCKET_TAKEN_MASK) + { + U_INTERNAL_DUMP("info[%u] = %u", nextIdx, info[nextIdx]) + + info[index] = info[nextIdx]-1; + + U_INTERNAL_DUMP("index = %u nextIdx = %u", index, nextIdx) + + U_INTERNAL_ASSERT_DIFFERS(index, nextIdx) + + setNodePointer(nextIdx); + + U_INTERNAL_DUMP("node->key = %V node->elem = %p node->hash = %u", node->key, node->elem, node->hash) + + lelem = node->elem; + lkey = node->key; + lhash = node->hash; + + setNodePointer(); + + U_INTERNAL_DUMP("node->key = %V node->elem = %p node->hash = %u", node->key, node->elem, node->hash) + + node->elem = lelem; + node->key = lkey; + node->hash = lhash; + + index = nextIdx; + nextIdx = (index+1) & mask; + } + + if (info[index]) info[index] = 0; + + --_length; U_INTERNAL_DUMP("_length = %u", _length) - - for (index = 0; index < _capacity; ++index) - { - if (table[index]) - { - node = table[index]; - - U_RETURN_POINTER(node, UHashMapNode); - } - } - - U_RETURN_POINTER(U_NULLPTR, UHashMapNode); -} - -bool UHashMap::next() -{ - U_TRACE_NO_PARAM(0, "UHashMap::next()") - - U_INTERNAL_DUMP("index = %u node = %p next = %p", index, node, node->next) - - if ((node = node->next)) U_RETURN(true); - - for (++index; index < _capacity; ++index) - { - if (table[index]) - { - node = table[index]; - - U_RETURN(true); - } - } - - U_RETURN(false); -} - -UHashMapNode* UHashMap::next(UHashMapNode* _node) -{ - U_TRACE(0, "UHashMap::next(%p)", _node) - - U_INTERNAL_DUMP("index = %u node = %p next = %p", index, node, node->next) - - if ((node = _node->next)) U_RETURN_POINTER(node, UHashMapNode); - - for (++index; index < _capacity; ++index) - { - if (table[index]) - { - node = table[index]; - - U_RETURN_POINTER(node, UHashMapNode); - } - } - - U_RETURN_POINTER(U_NULLPTR, UHashMapNode); -} - -void UHashMap::callForAllEntry(bPFprpv function) -{ - U_TRACE(0, "UHashMap::callForAllEntry(%p)", function) - -#ifdef DEBUG - int sum = 0, max = 0, min = 1024, width; -#endif - - U_INTERNAL_DUMP("_length = %u", _length) - - UHashMapNode* _node; - UHashMapNode* _next; - UHashMapNode** ptr; - UHashMapNode** end; - - for (end = (ptr = table) + _capacity; ptr < end; ++ptr) - { - if (*ptr) - { - _node = *ptr; - -# ifdef DEBUG - ++sum; - width = -1; -# endif - - do { -# ifdef DEBUG - ++width; -# endif - - _next = _node->next; - - if (function((UStringRep*)_node->key, (void*)_node->elem) == false) return; - } - while ((_node = _next)); - -# ifdef DEBUG - if (max < width) max = width; - if (min > width) min = width; -# endif - } - } - - U_INTERNAL_DUMP("collision(min,max) = (%3d,%3d) - distribution = %3f", min, max, (sum ? (double)_length / (double)sum : 0)) -} - -void UHashMap::getKeys(UVector& vec) -{ - U_TRACE(0, "UHashMap::getKeys(%p)", &vec) - - UHashMapNode* _node; - UHashMapNode* _next; - UHashMapNode** ptr; - UHashMapNode** end; - - for (end = (ptr = table) + _capacity; ptr < end; ++ptr) - { - if (*ptr) - { - _node = *ptr; - - do { - vec.UVector::push(_node->key); - - _next = _node->next; - } - while ((_node = _next)); - } - } -} - -void UHashMap::_callForAllEntrySorted(bPFprpv function) -{ - U_TRACE(0, "UHashMap::_callForAllEntrySorted(%p)", function) - - U_INTERNAL_ASSERT_MAJOR(_length, 1) - - UVector vkey(_length); - - getKeys(vkey); - - U_ASSERT_EQUALS(_length, vkey.size()) - - vkey.sort(ignoreCase()); - - U_INTERNAL_ASSERT(check_memory()) - - for (uint32_t i = 0, n = _length; i < n; ++i) - { - UStringRep* r = vkey.UVector::at(i); - - lookup(r); - - U_INTERNAL_ASSERT_POINTER(node) - - if (function(r, (void*)node->elem) == false) return; - } -} - -UString UHashMap::erase(const UString& _key) -{ - U_TRACE(0, "UHashMap::erase(%V)", _key.rep) - - UHashMap::lookup(_key); - - if (node) - { - UString str(elem()); - - U_INTERNAL_DUMP("str.reference() = %u", str.reference()) - - U_INTERNAL_ASSERT_MAJOR(str.reference(), 0) - - eraseAfterFind(); - - U_INTERNAL_DUMP("str.reference() = %u", str.reference()) - - U_RETURN_STRING(str); - } - - return UString::getStringNull(); } __pure bool UHashMap::operator==(const UHashMap& t) @@ -572,29 +372,17 @@ __pure bool UHashMap::operator==(const UHashMap& t) { U_INTERNAL_DUMP("_length = %u", _length) - UHashMapNode* _node; - UHashMapNode* _next; - UHashMapNode** ptr; - UHashMapNode** end; - - for (end = (ptr = t.table) + t._capacity; ptr < end; ++ptr) + for (uint32_t idx = 0; idx < t._capacity; ++idx) { - if (*ptr) + if ((t.info[idx] & U_IS_BUCKET_TAKEN_MASK) != 0) { - _node = *ptr; + t.setNodePointer(idx); - do { - _next = _node->next; - - UHashMap::lookup((UStringRep*)_node->key); - - if (node == U_NULLPTR || - ((UStringRep*)_node->elem)->equal(elem()) == false) - { - U_RETURN(false); - } + if (UHashMap::lookup((UStringRep*)t.node->key) == false || + ((UStringRep*)t.node->elem)->equal(elem()) == false) + { + U_RETURN(false); } - while ((_node = _next)); } } @@ -604,76 +392,6 @@ __pure bool UHashMap::operator==(const UHashMap& t) U_RETURN(false); } -// OPERATOR [] - -UString UHashMap::at(const UStringRep* _key) -{ - U_TRACE(0, "UHashMap::at(%V)", _key) - - UHashMap::lookup(_key); - - if (node) - { - UString str(elem()); - - U_RETURN_STRING(str); - } - - return UString::getStringNull(); -} - -UString UHashMap::operator[](const char* _key) -{ - U_TRACE(0, "UHashMap::operator[](%S)", _key) - - U_INTERNAL_ASSERT_POINTER(pkey) - - pkey->str = _key; - pkey->_length = u__strlen(_key, __PRETTY_FUNCTION__); - - return at(pkey); -} - -void* UHashMap::erase(const char* _key) -{ - U_TRACE(0, "UHashMap::erase(%S)", _key) - - U_INTERNAL_ASSERT_POINTER(pkey) - - pkey->str = _key; - pkey->_length = u__strlen(_key, __PRETTY_FUNCTION__); - - return erase(pkey); -} - -UString UHashMap::at(const char* _key, uint32_t keylen) -{ - U_TRACE(0, "UHashMap::at(%.*S,%u)", keylen, _key, keylen) - - U_INTERNAL_ASSERT_POINTER(pkey) - - pkey->str = _key; - pkey->_length = keylen; - - return at(pkey); -} - -bool UHashMap::find(const char* _key, uint32_t keylen) -{ - U_TRACE(0, "UHashMap::find(%.*S,%u)", keylen, _key, keylen) - - U_INTERNAL_ASSERT_POINTER(pkey) - - pkey->str = _key; - pkey->_length = keylen; - - lookup(pkey); - - if (node != U_NULLPTR) U_RETURN(true); - - U_RETURN(false); -} - uint32_t UHashMap::loadFromData(const char* ptr, uint32_t sz) { U_TRACE(0+256, "UHashMap::loadFromData(%.*S,%u)", sz, ptr, sz) @@ -815,95 +533,26 @@ __pure uint32_t UHashMap::getSpaceToDump() const if (_length) { uint32_t sz; - UHashMapNode* pnode; - UHashMapNode* pnext; - for (uint32_t _index = 0; _index < _capacity; ++_index) + for (uint32_t idx = 0; idx < _capacity; ++idx) { - pnode = table[_index]; + if ((info[idx] & U_IS_BUCKET_TAKEN_MASK) == 0) continue; - if (pnode == U_NULLPTR) continue; + setNodePointer(idx); -loop: U_INTERNAL_ASSERT_POINTER(pnode) + sz = node->key->size(); - sz = pnode->key->size(); - - U_INTERNAL_DUMP("pnode->key(%u) = %p %V", sz, pnode->key, pnode->key) + U_INTERNAL_DUMP("node->key(%u) = %p %V", sz, node->key, node->key) U_INTERNAL_ASSERT_MAJOR(sz, 0) - space += sz + 1 + ((UStringRep*)pnode->elem)->getSpaceToDump() + 1; - - if (pnode->next) - { - pnext = pnode->next; - - U_INTERNAL_ASSERT_POINTER(pnext) - U_INTERNAL_ASSERT_DIFFERS(pnode, pnext) - - pnode = pnext; - - goto loop; - } + space += sz + 1 + ((UStringRep*)node->elem)->getSpaceToDump() + 1; } } U_RETURN(space); } -bool UHashMap::empty() -{ - U_TRACE_NO_PARAM(0, "UHashMap::empty()") - - if (_length) - { - if (first()) - { - do { - UVector* _elem = elem(); - - if (_elem->empty() == false) U_RETURN(false); - } - while (next()); - } - } - - U_RETURN(true); -} - -void UHashMap::push(const UString& _key, const UString& str) -{ - U_TRACE(0, "UHashMap::push(%V,%V)", _key.rep, str.rep) - - UVector* _elem; - - UHashMap::lookup(_key); - - if (node) _elem = (UVector*) node->elem; - else - { - U_NEW(UVector, _elem, UVector); - - UHashMap::insertAfterFind(_key, _elem); - } - - _elem->push(str); -} - -void UHashMap::erase(const UString& _key, uint32_t pos) -{ - U_TRACE(0, "UHashMap::erase(%V,%u)", _key.rep, pos) - - UHashMap::lookup(_key); - - if (node) - { - UVector* _elem = (UVector*) node->elem; - - _elem->erase(pos); - } -} - // STREAMS #ifdef U_STDCPP_ENABLE @@ -993,31 +642,17 @@ U_EXPORT istream& operator>>(istream& is, UHashMap& t) // DEBUG # ifdef DEBUG -const char* UHashMapNode::dump(bool reset) const -{ - *UObjectIO::os << "elem " << elem << '\n' - << "hash " << hash << '\n' - << "key (UStringRep " << (void*)key << ")\n" - << "next (UHashMapNode " << (void*)next << ')'; - - if (reset) - { - UObjectIO::output(); - - return UObjectIO::buffer_output; - } - - return U_NULLPTR; -} - const char* UHashMap::dump(bool reset) const { - *UObjectIO::os << "hash " << hash << '\n' - << "index " << index << '\n' - << "table " << (void*)table << '\n' - << "_length " << _length << "\n" - << "_capacity " << _capacity << '\n' - << "node (UHashMapNode " << (void*)node << ')'; + *UObjectIO::os << "mask " << mask << '\n' + << "info " << (void*)info << '\n' + << "lhash " << lhash << '\n' + << "linfo " << linfo << '\n' + << "table " << (void*)table << '\n' + << "index " << index << '\n' + << "_length " << _length << "\n" + << "_capacity " << _capacity << '\n' + << "max_num_num_elements_allowed " << max_num_num_elements_allowed; if (reset) { diff --git a/src/ulib/container/vector.cpp b/src/ulib/container/vector.cpp index cc3cd73a..87b86558 100644 --- a/src/ulib/container/vector.cpp +++ b/src/ulib/container/vector.cpp @@ -301,24 +301,6 @@ __pure uint32_t UVector::find(const UString& str, bool ignore_case) U_RETURN(U_NOT_FOUND); } -// Check equality with string at pos - -__pure bool UVector::isEqual(uint32_t pos, const UString& str, bool ignore_case) -{ - U_TRACE(0, "UVector::isEqual(%u,%V,%b)", pos, str.rep, ignore_case) - - U_CHECK_MEMORY - - if (_length) - { - UStringRep* rep = UVector::at(pos); - - if (UStringRep::equal_lookup(rep, U_STRING_TO_PARAM(*rep), str.rep, str.size(), ignore_case)) U_RETURN(true); - } - - U_RETURN(false); -} - __pure uint32_t UVector::findSorted(const UString& str, bool ignore_case, bool bcouple) { U_TRACE(0, "UVector::findSorted(%V,%b,%b)", str.rep, ignore_case, bcouple) diff --git a/src/ulib/db/cdb.cpp b/src/ulib/db/cdb.cpp index e260d1b2..70ad9a80 100644 --- a/src/ulib/db/cdb.cpp +++ b/src/ulib/db/cdb.cpp @@ -738,6 +738,68 @@ UString UCDB::print() // Save memory hash table as constant database +static char* writeTo_ptr; +static UCDB* writeTo_cdb; +static pvPFpvpb writeTo_func; + +bool UCDB::writeTo(UStringRep* key, void* elem) // callWithDeleteForAllEntry()... +{ + U_TRACE(0, "UCDB::writeTo(%V,%p)", key, elem) + + UStringRep* value; + bool bdelete = false; + + if (writeTo_func == U_NULLPTR) value = (UStringRep*)UHashMap::node->elem; + else + { + value = (UStringRep*) writeTo_func((void*)UHashMap::node->elem, &bdelete); + + U_INTERNAL_DUMP("bdelete = %b", bdelete) + } + + if (value) + { + const UStringRep* k = UHashMap::node->key; + + uint32_t klen = k->size(), // key length + dlen = value->size(); // data length + + UCDB::cdb_record_header* _hr = (UCDB::cdb_record_header*) writeTo_ptr; + + u_put_unaligned32(_hr->klen, klen); + u_put_unaligned32(_hr->dlen, dlen); + + U_INTERNAL_DUMP("hr = { %u, %u }", klen, dlen) + + writeTo_ptr += sizeof(UCDB::cdb_record_header); + + U_MEMCPY(writeTo_ptr, k->data(), klen); + + U_INTERNAL_DUMP("key = %.*S", klen, writeTo_ptr) + + writeTo_ptr += klen; + + U_MEMCPY(writeTo_ptr, value->data(), dlen); + + U_INTERNAL_DUMP("data = %.*S", dlen, writeTo_ptr) + + writeTo_ptr += dlen; + + if (writeTo_func) + { + writeTo_cdb->nrecord++; + + value->release(); + } + } + + // check if asked to delete node of the table... + + if (bdelete) U_RETURN(true); + + U_RETURN(false); +} + bool UCDB::writeTo(UCDB& cdb, UHashMap* table, uint32_t tbl_space, pvPFpvpb func) { U_TRACE(1, "UCDB::writeTo(%p,%p,%u,%p)", &cdb, table, tbl_space, func) @@ -750,110 +812,14 @@ bool UCDB::writeTo(UCDB& cdb, UHashMap* table, uint32_t tbl_space, pvPFpv if (result) { - result = cdb.memmap(PROT_READ | PROT_WRITE); + if (cdb.memmap(PROT_READ | PROT_WRITE) == false) U_RETURN(false); - if (result == false) U_RETURN(false); + writeTo_ptr = (writeTo_cdb = &cdb)->start(); // init of DATA + writeTo_func = func; - bool bdelete; - UStringRep* value; - const UStringRep* _key; - char* ptr = cdb.start(); // init of DATA - UCDB::cdb_record_header* _hr; + table->callWithDeleteForAllEntry(writeTo); - U_INTERNAL_DUMP("table->_length = %u", table->_length) - - UHashMapNode* node; - UHashMapNode** pnode; - UHashMapNode** tbl = table->table; - - uint32_t klen; // key length - uint32_t dlen; // data length - - for (uint32_t index = 0, capacity = table->_capacity; index < capacity; ++index) - { - if (tbl[index]) - { - node = tbl[index]; - pnode = tbl + index; - - do { - if (func == U_NULLPTR) value = (UStringRep*) node->elem; - else - { - value = (UStringRep*) func((void*)node->elem, &bdelete); - - U_INTERNAL_DUMP("bdelete = %b", bdelete) - - if (bdelete) // ask for to delete node of table... - { - *pnode = node->next; // lo si toglie dalla lista collisioni... - - /** - * NB: it must be do in the function - * --------------------------------- - * elem = (T*) node->elem; - * - * u_destroy(elem); - * --------------------------------- - */ - - delete node; - - table->_length--; - } - } - - if (value) - { - _key = node->key; - - klen = _key->size(); // key length - dlen = value->size(); // data length - - _hr = (UCDB::cdb_record_header*) ptr; - - u_put_unaligned32(_hr->klen, klen); - u_put_unaligned32(_hr->dlen, dlen); - - U_INTERNAL_DUMP("hr = { %u, %u }", klen, dlen) - - ptr += sizeof(UCDB::cdb_record_header); - - U_MEMCPY(ptr, _key->data(), klen); - - U_INTERNAL_DUMP("key = %.*S", klen, ptr) - - ptr += klen; - - U_MEMCPY(ptr, value->data(), dlen); - - U_INTERNAL_DUMP("data = %.*S", dlen, ptr) - - ptr += dlen; - - if (func) - { - cdb.nrecord++; - - value->release(); - } - } - - // check if asked to delete node of the table... - - if (func == U_NULLPTR || - bdelete == false) - { - pnode = &(*pnode)->next; - } - } - while ((node = *pnode)); - } - } - - U_INTERNAL_DUMP("table->_length = %u", table->_length) - - cdb.hr = (UCDB::cdb_record_header*) ptr; // end of DATA + cdb.hr = (UCDB::cdb_record_header*) writeTo_ptr; // end of DATA uint32_t pos = cdb.makeFinish(true); diff --git a/src/ulib/file.cpp b/src/ulib/file.cpp index d7df6bc4..a76eac8c 100644 --- a/src/ulib/file.cpp +++ b/src/ulib/file.cpp @@ -51,17 +51,8 @@ void UFile::inc_num_file_object(UFile* pthis) U_INTERNAL_ASSERT_EQUALS((void*)pthis, (void*)&(pthis->st_dev)) } -void UFile::dec_num_file_object(int fd) -{ - --num_file_object; - - if (fd != -1) U_WARNING("File descriptor %d not closed...", fd); -} - -void UFile::chk_num_file_object() -{ - if (num_file_object) U_WARNING("UFile::chdir() with num file object = %d", num_file_object); -} +void UFile::chk_num_file_object() { if (num_file_object) U_WARNING("UFile::chdir() with num file object = %d", num_file_object); } +void UFile::dec_num_file_object(int fd) { --num_file_object; if (fd != -1) U_WARNING("File descriptor %d not closed...", fd); } #endif #ifndef MREMAP_MAYMOVE @@ -72,69 +63,21 @@ void UFile::setPathRelativ(const UString* environment) { U_TRACE(0, "UFile::setPathRelativ(%p)", environment) - U_CHECK_MEMORY - U_INTERNAL_ASSERT(pathname) - reset(); - - const char* ptr = (pathname.isNullTerminated() ? pathname.data() : pathname.c_str()); - - char c = *ptr; + char c = pathname.first_char(); if (c == '~' || c == '$') { UString x = UStringExt::expandPath(pathname, environment); - if (x) - { - pathname = x; - - ptr = pathname.data(); - } + if (x) pathname = x; } - // NB: the string can be not writable... - - path_relativ_len = pathname.size(); - path_relativ = u_getPathRelativ(ptr, &path_relativ_len); - - U_INTERNAL_ASSERT_MAJOR(path_relativ_len, 0) - - // we don't need this... (I think) - - /* - if (pathname.writeable() && - pathname.size() != path_relativ_len) - { - path_relativ[path_relativ_len] = '\0'; - } - */ - - U_INTERNAL_DUMP("u_cwd(%u) = %S", u_cwd_len, u_cwd) - U_INTERNAL_DUMP("pathname(%u) = %V", pathname.size(), pathname.rep) - U_INTERNAL_DUMP("path_relativ(%u) = %.*S", path_relativ_len, path_relativ_len, path_relativ) + setPathRelativ(); } -void UFile::setRoot() -{ - U_TRACE_NO_PARAM(0, "UFile::setRoot()") - - reset(); - - pathname.setConstant(U_CONSTANT_TO_PARAM("/")); - - st_mode = S_IFDIR|0755; - path_relativ = pathname.data(); - path_relativ_len = 1; - - U_INTERNAL_DUMP("u_cwd(%u) = %S", u_cwd_len, u_cwd) - U_INTERNAL_DUMP("path_relativ(%u) = %.*S", path_relativ_len, path_relativ_len, path_relativ) -} - -// gcc - call is unlikely and code size would grow - bool UFile::open(int flags) { U_TRACE(0, "UFile::open(%d)", flags) @@ -155,20 +98,6 @@ bool UFile::open(int flags) U_RETURN(false); } -int UFile::open(const char* _pathname, int flags, mode_t mode) -{ - U_TRACE(1, "UFile::open(%S,%d,%d)", _pathname, flags, mode) - - U_INTERNAL_ASSERT_POINTER(_pathname) - U_INTERNAL_ASSERT_MAJOR(u__strlen(_pathname, __PRETTY_FUNCTION__), 0) - - // NB: we centralize here O_BINARY... - - int _fd = U_SYSCALL(open, "%S,%d,%d", U_PATH_CONV(_pathname), flags | O_CLOEXEC | O_BINARY, mode); - - U_RETURN(_fd); -} - bool UFile::creat(int flags, mode_t mode) { U_TRACE(0, "UFile::creat(%d,%d)", flags, mode) @@ -727,8 +656,7 @@ bool UFile::memmap(int prot, UString* str, uint32_t offset, uint32_t length) if (map != (char*)MAP_FAILED) { munmap(map, map_size); - - map_size = 0; + map_size = 0; } int flags = MAP_SHARED; @@ -774,7 +702,7 @@ void UFile::munmap() U_INTERNAL_ASSERT_POINTER(path_relativ) - U_INTERNAL_ASSERT_MAJOR(map_size,0UL) + U_INTERNAL_ASSERT_MAJOR(map_size, 0) U_INTERNAL_ASSERT_DIFFERS(map,(char*)MAP_FAILED) UFile::munmap(map, map_size); @@ -877,50 +805,28 @@ UString UFile::getContent(bool brdonly, bool bstat, bool bmap) U_RETURN_STRING(fileContent); } -UString UFile::contentOf(const UString& _pathname, int flags, bool bstat, const UString* environment) +UString UFile::contentOf(const UString& pathname, const UString& pinclude) { - U_TRACE(0, "UFile::contentOf(%V,%d,%b,%p)", _pathname.rep, flags, bstat, environment) + U_TRACE(0, "UFile::contentOf(%V,%V)", pathname.rep, pinclude.rep) - U_INTERNAL_ASSERT(_pathname) + UFile file(pathname); - UFile file; - UString content; - - file.reset(); - file.setPath(_pathname, environment); - - if (file.open(flags)) content = file.getContent((((flags & O_RDWR) | (flags & O_WRONLY)) == 0), bstat); - - U_RETURN_STRING(content); -} - -UString UFile::contentOf(const UString& _pathname, const UString& pinclude) -{ - U_TRACE(0, "UFile::contentOf(%V,%V)", _pathname.rep, pinclude.rep) - - UFile file; - UString content; - - file.reset(); - file.setPath(_pathname); - - if (file.open(O_RDONLY)) - { - content = file.getContent(); - - U_RETURN_STRING(content); - } + if (file.open()) return file.getContent(); if (pinclude) { - file.reset(); + UString x(U_CAPACITY); - file.setPath(pinclude + '/' + UStringExt::basename(_pathname)); + (void) x.append(pinclude); + x.push_back('/'); + (void) x.append(UStringExt::basename(pathname)); - if (file.open(O_RDONLY)) content = file.getContent(); + file.setPath(x); + + if (file.open()) return file.getContent(); } - U_RETURN_STRING(content); + return UString::getStringNull(); } void UFile::printf(const char* format, uint32_t fmt_size, ...) diff --git a/src/ulib/mime/header.cpp b/src/ulib/mime/header.cpp index 39c65093..ed40b80b 100644 --- a/src/ulib/mime/header.cpp +++ b/src/ulib/mime/header.cpp @@ -108,7 +108,7 @@ uint32_t UMimeHeader::parse(const char* ptr, uint32_t len) // Check for duplication of header - if (containsHeader(key) == false) table.insertAfterFind(key, value); + if (containsHeader(key) == false) table.insertAfterFind(value); else { UStringRep* rep = table.elem(); @@ -313,9 +313,12 @@ void UMimeHeader::writeHeaders(UString& buffer) if (table.first()) { + UStringRep* value; + const UStringRep* key; + do { - const UStringRep* key = table.key(); - UStringRep* value = table.elem(); + key = table.key(); + value = table.elem(); tmp.setBuffer(key->size() + 2 + value->size() + 2); @@ -373,9 +376,12 @@ U_EXPORT ostream& operator<<(ostream& os, UMimeHeader& h) if (h.table.first()) { + UStringRep* value; + const UStringRep* key; + do { - const UStringRep* key = h.table.key(); - UStringRep* value = h.table.elem(); + key = h.table.key(); + value = h.table.elem(); os.write(key->data(), key->size()); os.write(": ", 2); diff --git a/src/ulib/net/server/plugin/mod_http.cpp b/src/ulib/net/server/plugin/mod_http.cpp index 47dac987..7e609cf5 100644 --- a/src/ulib/net/server/plugin/mod_http.cpp +++ b/src/ulib/net/server/plugin/mod_http.cpp @@ -569,8 +569,6 @@ int UHttpPlugIn::handlerRun() // NB: we use this method instead of handlerInit() } } - U_ASSERT(UHTTP::cache_file_check_memory()) - U_SET_MODULE_NAME(usp_init); #ifndef U_LOG_DISABLE diff --git a/src/ulib/net/server/plugin/mod_ssi.cpp b/src/ulib/net/server/plugin/mod_ssi.cpp index cc93f92b..d5f7fc3b 100644 --- a/src/ulib/net/server/plugin/mod_ssi.cpp +++ b/src/ulib/net/server/plugin/mod_ssi.cpp @@ -950,7 +950,7 @@ int USSIPlugIn::handlerConfig(UFileConfig& cfg) if (x) { - U_NEW(UString, environment, UString(UStringExt::prepareForEnvironmentVar(UFile::contentOf(x)))); + U_NEW(UString, environment, UString(UStringExt::prepareForEnvironmentVar(UFile::contentOf(x, O_RDONLY, false, U_NULLPTR)))); const char* home = U_SYSCALL(getenv, "%S", "HOME"); diff --git a/src/ulib/net/server/plugin/usp/usp_translator.cpp b/src/ulib/net/server/plugin/usp/usp_translator.cpp index fbac5d89..297b1713 100644 --- a/src/ulib/net/server/plugin/usp/usp_translator.cpp +++ b/src/ulib/net/server/plugin/usp/usp_translator.cpp @@ -30,52 +30,6 @@ #include -#define USP_SESSION_INIT \ -"\n\t\nstatic void usp_init_%.*s()\n" \ -"{\n" \ -"\tU_TRACE(5, \"::usp_init_%.*s()\")\n" \ -"\t\n" \ -"%s" \ -"%s" \ -"\n\tif (UHTTP::db_session == U_NULLPTR) UHTTP::initSession();\n" \ -"}" - -#define USP_TEMPLATE \ -"// %.*s.cpp - dynamic page translation (%.*s.usp => %.*s.cpp)\n" \ -"\t\n" \ -"#include \n" \ -"\t\n" \ -"%v" \ -"\t\n" \ -"\t\n" \ -"extern \"C\" {\n" \ -"extern U_EXPORT void runDynamicPage_%.*s(int param);\n" \ -" U_EXPORT void runDynamicPage_%.*s(int param)\n" \ -"{\n" \ -"\tU_TRACE(0, \"::runDynamicPage_%.*s(%%d)\", param)\n" \ -"\t\n" \ -"%s" \ -"\t\n" \ -"\tif (param)\n" \ -"\t\t{\n" \ -"%s" \ -"%s" \ -"%s" \ -"%s" \ -"%s" \ -"%s" \ -"\t\t}\n" \ -"\t\n" \ -"%v" \ -"%v" \ -"\t\n" \ -"%v" \ -"%v" \ -"%v" \ -"%s" \ -"\t\n" \ -"} }\n" - class Application : public UApplication { public: @@ -706,11 +660,19 @@ loop: distance = t.getDistance(); (void) declaration.reserve(500U); - declaration.snprintf_add(U_CONSTANT_TO_PARAM(USP_SESSION_INIT), - basename_sz, basename_ptr, - basename_sz, basename_ptr, - (bsession ? "\n\tif (UHTTP::data_session == U_NULLPTR) U_NEW(UDataSession, UHTTP::data_session, UDataSession);\n\t" : ""), - (bstorage ? "\n\tif (UHTTP::data_storage == U_NULLPTR) { U_NEW(UDataSession, UHTTP::data_storage, UDataSession(*UString::str_storage_keyid)); }\n\t" : "")); + declaration.snprintf_add(U_CONSTANT_TO_PARAM( + "\n\t\nstatic void usp_init_%.*s()\n" + "{\n" + "\tU_TRACE(5, \"::usp_init_%.*s()\")\n" + "\t\n" + "%s" + "%s" + "\n\tif (UHTTP::db_session == U_NULLPTR) UHTTP::initSession();\n" + "}"), + basename_sz, basename_ptr, + basename_sz, basename_ptr, + (bsession ? "\n\tif (UHTTP::data_session == U_NULLPTR) U_NEW(UDataSession, UHTTP::data_session, UDataSession);\n\t" : ""), + (bstorage ? "\n\tif (UHTTP::data_storage == U_NULLPTR) { U_NEW(UDataSession, UHTTP::data_storage, UDataSession(*UString::str_storage_keyid)); }\n\t" : "")); } if (binit) (void) u__snprintf(ptr1, 100, U_CONSTANT_TO_PARAM("\n\t\tif (param == U_DPAGE_INIT) { usp_init_%.*s(); return; }\n\t"), basename_sz, basename_ptr); @@ -759,31 +721,65 @@ loop: distance = t.getDistance(); "\n\t(void) UClientImage_Base::wbuffer->insert(0, U_CONSTANT_TO_PARAM(%v));\n\t\n"), n, encoded.rep); } - UString result(1024U + sizeof(USP_TEMPLATE) + declaration.size() + http_header.size() + output0.size() + output1.size() + output2.size()); + UString result(1024U + declaration.size() + http_header.size() + output0.size() + output1.size() + output2.size()); - result.snprintf(U_CONSTANT_TO_PARAM(USP_TEMPLATE), - basename_sz, basename_ptr, - basename_sz, basename_ptr, - basename_sz, basename_ptr, - declaration.rep, - basename_sz, basename_ptr, - basename_sz, basename_ptr, - basename_sz, basename_ptr, - bvar ? "\n\tuint32_t usp_sz = 0;" - "\n\tchar usp_buffer[10 * 4096];\n" - : "", - ptr1, - ptr2, - ptr3, - ptr4, - ptr5, - ptr6, - vcode.rep, - http_header.rep, - output0.rep, - output1.rep, - output2.rep, - ptr7); + result.snprintf(U_CONSTANT_TO_PARAM( + "// %.*s.cpp - dynamic page translation (%.*s.usp => %.*s.cpp)\n" + "\t\n" + "#include \n" + "\t\n" + "%v" + "\t\n" + "\t\n" + "extern \"C\" {\n" + "extern U_EXPORT void runDynamicPage_%.*s(int param);\n" + " U_EXPORT void runDynamicPage_%.*s(int param)\n" + "{\n" + "\tU_TRACE(0, \"::runDynamicPage_%.*s(%%d)\", param)\n" + "\t\n" + "%s" + "\t\n" + "\tif (param)\n" + "\t\t{\n" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s" + "\t\t}\n" + "\t\n" + "%v" + "%v" + "\t\n" + "%v" + "%v" + "%v" + "%s" + "\t\n" + "} }\n"), + basename_sz, basename_ptr, + basename_sz, basename_ptr, + basename_sz, basename_ptr, + declaration.rep, + basename_sz, basename_ptr, + basename_sz, basename_ptr, + basename_sz, basename_ptr, + bvar ? "\n\tuint32_t usp_sz = 0;" + "\n\tchar usp_buffer[10 * 4096];\n" + : "", + ptr1, + ptr2, + ptr3, + ptr4, + ptr5, + ptr6, + vcode.rep, + http_header.rep, + output0.rep, + output1.rep, + output2.rep, + ptr7); UString name(200U); diff --git a/src/ulib/notifier.cpp b/src/ulib/notifier.cpp index 103d29e3..4bd032ea 100644 --- a/src/ulib/notifier.cpp +++ b/src/ulib/notifier.cpp @@ -1069,9 +1069,9 @@ void UNotifier::callForAllEntryDynamic(bPFpv function) } } - UGenericHashMap::UGenericHashMapNode* _node; + UGenericHashMap::UGenericHashMapNode* pnode; - if ((_node = hi_map_fd->first())) + if ((pnode = hi_map_fd->first())) { do { item = hi_map_fd->elem(); @@ -1080,7 +1080,7 @@ void UNotifier::callForAllEntryDynamic(bPFpv function) if (function(item)) { - U_DEBUG("UNotifier::callForAllEntryDynamic(): hi_map_fd(%p) = %p %u", _node, item, item->fd); + U_DEBUG("UNotifier::callForAllEntryDynamic(): hi_map_fd(%p) = %p %u", pnode, item, item->fd); handlerDelete(item); @@ -1089,7 +1089,7 @@ void UNotifier::callForAllEntryDynamic(bPFpv function) if (num_connection == min_connection) return; } } - while ((_node = hi_map_fd->next(_node))); + while ((pnode = hi_map_fd->next(pnode))); } } @@ -1125,9 +1125,9 @@ void UNotifier::clear() } } - UGenericHashMap::UGenericHashMapNode* _node; + UGenericHashMap::UGenericHashMapNode* pnode; - if ((_node = hi_map_fd->first())) + if ((pnode = hi_map_fd->first())) { do { item = hi_map_fd->elem(); @@ -1136,7 +1136,7 @@ void UNotifier::clear() if (item->fd != -1) handlerDelete(item); } - while ((_node = hi_map_fd->next(_node))); + while ((pnode = hi_map_fd->next(pnode))); } } diff --git a/src/ulib/string.cpp b/src/ulib/string.cpp index d68c2e39..41ab6d11 100644 --- a/src/ulib/string.cpp +++ b/src/ulib/string.cpp @@ -19,6 +19,7 @@ vpFpcu UString::printValueToBuffer; UString* UString::string_null = ULib::uustringnull.p2; UStringRep* UStringRep::string_rep_null = ULib::uustringrepnull.p2; +UStringRep* UString::pkey; // OPTMIZE APPEND (BUFFERED) char* UString::appbuf; @@ -351,7 +352,7 @@ void UString::str_allocate(int which) U_INTERNAL_ASSERT_EQUALS(str_nostat, U_NULLPTR) U_INTERNAL_ASSERT_EQUALS(str_tsa, U_NULLPTR) U_INTERNAL_ASSERT_EQUALS(str_soap, U_NULLPTR) - U_INTERNAL_ASSERT_EQUALS(UHashMap::pkey, U_NULLPTR) + U_INTERNAL_ASSERT_EQUALS(pkey, U_NULLPTR) U_NEW_ULIB_OBJECT(UString, str_host, UString(stringrep_storage+0)); U_NEW_ULIB_OBJECT(UString, str_chunked, UString(stringrep_storage+1)); @@ -373,9 +374,9 @@ void UString::str_allocate(int which) uustringrep key1 = { stringrep_storage+17 }; - UHashMap::pkey = key1.p2; + pkey = key1.p2; - U_INTERNAL_ASSERT(UHashMap::pkey->invariant()) + U_INTERNAL_ASSERT(pkey->invariant()) U_INTERNAL_ASSERT_EQUALS(*str_without_mac, "00:00:00:00:00:00") U_INTERNAL_ASSERT_EQUALS(*str_CLIENT_QUEUE_DIR, "/tmp/uclient") diff --git a/src/ulib/utility/dir_walk.cpp b/src/ulib/utility/dir_walk.cpp index 5a2446e7..723534af 100644 --- a/src/ulib/utility/dir_walk.cpp +++ b/src/ulib/utility/dir_walk.cpp @@ -462,7 +462,7 @@ U_NO_EXPORT int UDirWalk::cmp_modify(const void* a, const void* b) (void) ra->stat(); - cache_file_for_compare->insertAfterFind(key, ra); + cache_file_for_compare->insertAfterFind(ra); } UFile* rb = (*cache_file_for_compare)[*(UStringRep**)b]; @@ -475,7 +475,7 @@ U_NO_EXPORT int UDirWalk::cmp_modify(const void* a, const void* b) (void) rb->stat(); - cache_file_for_compare->insertAfterFind(key, rb); + cache_file_for_compare->insertAfterFind(rb); } U_INTERNAL_DUMP("ra = %.*S", U_FILE_TO_TRACE(*ra)) diff --git a/src/ulib/utility/http2.cpp b/src/ulib/utility/http2.cpp index 81194276..608cf65b 100644 --- a/src/ulib/utility/http2.cpp +++ b/src/ulib/utility/http2.cpp @@ -122,9 +122,9 @@ const UHTTP2::Settings UHTTP2::settings = { /* max_header_list_size */ UINT32_MAX }; -UHTTP2::Connection::Connection() : itable(53, setIndexStaticTable) +UHTTP2::Connection::Connection() : itable(64, setIndexStaticTable) #ifdef DEBUG -, dtable(53, setIndexStaticTable) +, dtable(64, setIndexStaticTable) #endif { U_TRACE_REGISTER_OBJECT(0, Connection, "", 0) @@ -1057,7 +1057,7 @@ check1: } } - table->hash = name.hashIgnoreCase(); + UHashMap::lhash = name.hashIgnoreCase(); goto insert; } @@ -1079,7 +1079,7 @@ check2: name._assign(entry->name); - table->hash = entry->name->hashIgnoreCase(); + UHashMap::lhash = entry->name->hashIgnoreCase(); if (binsert_dynamic_table == false) { @@ -1154,9 +1154,9 @@ cdefault: name._assign(entry->name); - table->hash = hash_static_table[index]; + UHashMap::lhash = hash_static_table[index]; - U_INTERNAL_DUMP("table->hash = %u name = %V value = %V", table->hash, name.rep, value.rep) + U_INTERNAL_DUMP("UHashMap::lhash = %u name = %V value = %V", UHashMap::lhash, name.rep, value.rep) goto insert; @@ -1164,7 +1164,7 @@ case_38: // host name = *UString::str_host; - table->hash = hash_static_table[37]; // host + UHashMap::lhash = hash_static_table[37]; // host goto host; @@ -1172,7 +1172,7 @@ case_1: // authority (a.k.a. the Host header) name = *UString::str_authority; - table->hash = hash_static_table[0]; // authority + UHashMap::lhash = hash_static_table[0]; // authority host: U_INTERNAL_ASSERT_EQUALS(bdecodeHeadersDebug, false) @@ -1337,7 +1337,7 @@ case_4_5: // :path => / /index.html setURI(value); } - table->hash = hash_static_table[3]; // path + UHashMap::lhash = hash_static_table[3]; // path goto insert; @@ -1415,7 +1415,7 @@ case_14: // :status 500 if (isHpackError()) return; } - table->hash = hash_static_table[7]; // status + UHashMap::lhash = hash_static_table[7]; // status goto insert; } @@ -1448,7 +1448,7 @@ case_16: // accept-encoding: gzip, deflate setEncoding(value); - table->hash = hash_static_table[15]; // accept_encoding + UHashMap::lhash = hash_static_table[15]; // accept_encoding goto insert; @@ -1474,7 +1474,7 @@ case_17: // accept-language U_INTERNAL_DUMP("Accept-Language: = %.*S", U_HTTP_ACCEPT_LANGUAGE_TO_TRACE) - table->hash = hash_static_table[16]; // accept_language + UHashMap::lhash = hash_static_table[16]; // accept_language goto insert; @@ -1500,7 +1500,7 @@ case_19: // accept U_INTERNAL_DUMP("Accept: = %.*S", U_HTTP_ACCEPT_TO_TRACE) - table->hash = hash_static_table[18]; // accept + UHashMap::lhash = hash_static_table[18]; // accept goto insert; @@ -1528,7 +1528,7 @@ case_28: // content_length U_INTERNAL_DUMP("Content-Length: = %.*S pStream->clength = %u", U_STRING_TO_TRACE(value), pStream->clength) } - table->hash = hash_static_table[27]; // content_length + UHashMap::lhash = hash_static_table[27]; // content_length goto insert; @@ -1557,7 +1557,7 @@ case_31: // content_type U_INTERNAL_DUMP("Content-Type(%u): = %.*S", U_http_content_type_len, U_HTTP_CTYPE_TO_TRACE) } - table->hash = hash_static_table[30]; // content_type + UHashMap::lhash = hash_static_table[30]; // content_type goto insert; @@ -1585,7 +1585,7 @@ case_32: // cookie U_INTERNAL_DUMP("Cookie(%u): = %.*S", U_http_info.cookie_len, U_HTTP_COOKIE_TO_TRACE) - table->hash = hash_static_table[31]; // cookie + UHashMap::lhash = hash_static_table[31]; // cookie goto insert; @@ -1614,7 +1614,7 @@ case_35: // expect { name = *UString::str_expect; - table->hash = hash_static_table[34]; // expect + UHashMap::lhash = hash_static_table[34]; // expect goto insert; } @@ -1642,7 +1642,7 @@ case_40: // if-modified-since U_INTERNAL_DUMP("If-Modified-Since = %u", U_http_info.if_modified_since) - table->hash = hash_static_table[39]; // if_modified_since + UHashMap::lhash = hash_static_table[39]; // if_modified_since goto insert; @@ -1668,7 +1668,7 @@ case_50: // range U_INTERNAL_DUMP("Range = %.*S", U_HTTP_RANGE_TO_TRACE) - table->hash = hash_static_table[49]; // range + UHashMap::lhash = hash_static_table[49]; // range goto insert; @@ -1694,7 +1694,7 @@ case_51: // referer U_INTERNAL_DUMP("Referer(%u): = %.*S", U_http_info.referer_len, U_HTTP_REFERER_TO_TRACE) - table->hash = hash_static_table[50]; // referer + UHashMap::lhash = hash_static_table[50]; // referer goto insert; @@ -1728,12 +1728,12 @@ case_58: // user-agent U_INTERNAL_DUMP("User-Agent: = %.*S", U_HTTP_USER_AGENT_TO_TRACE) - table->hash = hash_static_table[57]; // user_agent + UHashMap::lhash = hash_static_table[57]; // user_agent insert: U_INTERNAL_ASSERT(name) U_INTERNAL_ASSERT(value) - U_INTERNAL_ASSERT(table->hash) + U_INTERNAL_ASSERT(UHashMap::lhash) U_INTERNAL_DUMP("dyntbl->num_entries = %u binsert_dynamic_table = %b", dyntbl->num_entries, binsert_dynamic_table) @@ -1806,7 +1806,7 @@ void UHTTP2::decodeHeaders() if (U_http_info.uri_len == 0) { - table->hash = hash_static_table[3]; // path + UHashMap::lhash = hash_static_table[3]; // path UString value = table->at(UString::str_path->rep); @@ -1818,7 +1818,7 @@ void UHTTP2::decodeHeaders() if (U_http_host_len == 0) { - table->hash = hash_static_table[0]; // authority + UHashMap::lhash = hash_static_table[0]; // authority UString value = table->at(UString::str_authority->rep); @@ -1832,7 +1832,7 @@ void UHTTP2::decodeHeaders() if (U_http_info.user_agent_len == 0) { - table->hash = hash_static_table[57]; // user-agent + UHashMap::lhash = hash_static_table[57]; // user-agent UString value = table->at(UString::str_user_agent->rep); @@ -1847,7 +1847,7 @@ void UHTTP2::decodeHeaders() if (U_http_is_accept_gzip == false) { - table->hash = hash_static_table[15]; // accept-encoding + UHashMap::lhash = hash_static_table[15]; // accept-encoding UString value = table->at(UString::str_accept_encoding->rep); @@ -1946,7 +1946,7 @@ void UHTTP2::manageHeaders() UHashMap* table = &(pConnection->itable); - table->hash = u_hash_ignore_case((unsigned char*)U_CONSTANT_TO_PARAM("trailer")); + UHashMap::lhash = u_hash_ignore_case((unsigned char*)U_CONSTANT_TO_PARAM("trailer")); UString trailer = table->at(U_CONSTANT_TO_PARAM("trailer")); @@ -3068,11 +3068,9 @@ void UHTTP2::downgradeRequest() if (U_http_is_accept_gzip) { - pConnection->itable.hash = hash_static_table[15]; // accept_encoding + UHashMap::lhash = hash_static_table[15]; // accept_encoding - pConnection->itable.lookup(hpack_static_table[15].name); - - U_INTERNAL_ASSERT_POINTER(pConnection->itable.node) + (void) pConnection->itable.lookup(hpack_static_table[15].name); UClientImage_Base::request->snprintf_add(U_CONSTANT_TO_PARAM("Accept-Encoding: %v\r\n"), pConnection->itable.elem()); } diff --git a/src/ulib/utility/uhttp.cpp b/src/ulib/utility/uhttp.cpp index 7360dda4..bdaacd83 100644 --- a/src/ulib/utility/uhttp.cpp +++ b/src/ulib/utility/uhttp.cpp @@ -1149,15 +1149,13 @@ void UHTTP::init() U_ASSERT_MAJOR(cache_file->size(), 0) U_SRV_LOG("Loaded cache file store: %V", cache_file_store->rep); - - U_ASSERT(cache_file_check_memory()) } # endif } sz = n + (15 * (n / 100)) + 32; - if (sz > cache_file->capacity()) cache_file->reserve(u_nextPowerOfTwo(sz)); + if (sz > cache_file->capacity()) cache_file->allocate(u_nextPowerOfTwo(sz)); U_INTERNAL_ASSERT_POINTER(pathname) @@ -1224,8 +1222,6 @@ void UHTTP::init() } #endif - U_ASSERT(cache_file_check_memory()) - UServices::generateKey(UServices::key, U_NULLPTR); // for ULib facility request TODO session cookies... U_INTERNAL_DUMP("htdigest = %p htpasswd = %p", htdigest, htpasswd) @@ -1250,8 +1246,6 @@ void UHTTP::init() U_ASSERT_MAJOR(cache_file->size(), 0) U_SRV_LOG("Loaded cache icon store for directory listing"); - - U_ASSERT(cache_file_check_memory()) } } @@ -1272,8 +1266,6 @@ void UHTTP::init() U_ASSERT_MAJOR(cache_file->size(), 0) U_SRV_LOG("Loaded cache favicon.ico"); - - U_ASSERT(cache_file_check_memory()) } #ifdef U_HTML_PAGINATION_SUPPORT // manage css for HTML Pagination @@ -1292,8 +1284,6 @@ void UHTTP::init() U_ASSERT_MAJOR(cache_file->size(), 0) U_SRV_LOG("Loaded cache css store for HTML pagination"); - - U_ASSERT(cache_file_check_memory()) } #endif @@ -1358,34 +1348,6 @@ void UHTTP::init() #endif } -#ifdef DEBUG -U_NO_EXPORT bool UHTTP::check_memory(UStringRep* key, void* value) -{ - U_TRACE(0, "UHTTP::check_memory(%V,%p)", key, value) - - U_INTERNAL_ASSERT_POINTER(value) - - UHTTP::UFileCacheData* cptr = (UHTTP::UFileCacheData*)value; - - if (cptr->array) (void) cptr->array->check_memory(); - - U_RETURN(true); -} - -bool UHTTP::cache_file_check_memory() -{ - U_TRACE_NO_PARAM(0, "UHTTP::cache_file_check_memory()") - - U_INTERNAL_ASSERT_POINTER(cache_file) - - cache_file->check_memory(); - - cache_file->callForAllEntry(check_memory); - - U_RETURN(true); -} -#endif - #ifdef U_ALIAS void UHTTP::setGlobalAlias(const UString& _alias) // NB: automatic alias for all uri request without suffix... { @@ -2247,7 +2209,7 @@ const char* UHTTP::getHeaderValuePtr(const char* name, uint32_t name_len, bool n if (U_http_version == '2') { - UHTTP2::pConnection->itable.hash = u_hash_ignore_case((unsigned char*)name, name_len); + UHashMap::lhash = u_hash_ignore_case((unsigned char*)name, name_len); *UClientImage_Base::request = UHTTP2::pConnection->itable.at(name, name_len); @@ -3586,7 +3548,8 @@ U_NO_EXPORT bool UHTTP::runDynamicPage() U_INTERNAL_ASSERT_MINOR(n, 4096) for (i = 0; i < n; ++i) argv[i] = (*form_name_value)[i].c_str(); - argv[i] = U_NULLPTR; + + argv[i] = U_NULLPTR; (void) csp->prog_main(n, argv); @@ -9088,7 +9051,7 @@ nocontent: UClientImage_Base::setCloseConnection(); # ifndef USE_HARDWARE_CRC32 db_not_found->UCDB::setHash(ptr, len); # else - db_not_found->UCDB::setHash(cache_file->hash); + db_not_found->UCDB::setHash(UHashMap::lhash); # endif if (db_not_found->_fetch()) diff --git a/tests/base/test_sprintf.c b/tests/base/test_sprintf.c index bdcd85f4..5a24a309 100644 --- a/tests/base/test_sprintf.c +++ b/tests/base/test_sprintf.c @@ -93,6 +93,7 @@ static void fp_test(void) { char buf[7]; char tp[20]; + int i, j, k, l; char* prefix = buf; puts("\nFormatted output test"); @@ -101,13 +102,13 @@ static void fp_test(void) strcpy(prefix, "%"); - for (int i = 0; i < 2; i++) + for (i = 0; i < 2; i++) { - for (int j = 0; j < 2; j++) + for (j = 0; j < 2; j++) { - for (int k = 0; k < 2; k++) + for (k = 0; k < 2; k++) { - for (int l = 0; l < 2; l++) + for (l = 0; l < 2; l++) { strcpy(prefix, "%"); if (i == 0) strcat(prefix, "-"); diff --git a/tests/ulib/Makefile.am b/tests/ulib/Makefile.am index 3f8d7a25..b104b9e5 100644 --- a/tests/ulib/Makefile.am +++ b/tests/ulib/Makefile.am @@ -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_smtp test_pop3 test_imap test_hash_map ## 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 + tokenizer.test query_parser.test multipart.test command.test json.test hash_map.test ## pop3.test imap.test smtp.test dialog.test redis.test elasticsearch.test twilio.test if ENABLE_SHARED @@ -101,6 +101,7 @@ test_server_SOURCES = test_server.cpp 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 if PTHREAD PRG += test_thread @@ -241,7 +242,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 ../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 ../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 f1024623..6f5a7ac9 100644 --- a/tests/ulib/Makefile.in +++ b/tests/ulib/Makefile.in @@ -226,14 +226,14 @@ am__EXEEXT_19 = test_timeval$(EXEEXT) test_timer$(EXEEXT) \ test_multipart$(EXEEXT) test_command$(EXEEXT) \ test_dialog$(EXEEXT) test_json$(EXEEXT) test_redis$(EXEEXT) \ test_elasticsearch$(EXEEXT) test_smtp$(EXEEXT) \ - test_pop3$(EXEEXT) test_imap$(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_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) am_test_application_OBJECTS = test_application.$(OBJEXT) test_application_OBJECTS = $(am_test_application_OBJECTS) test_application_LDADD = $(LDADD) @@ -336,6 +336,10 @@ am_test_ftp_OBJECTS = test_ftp.$(OBJEXT) test_ftp_OBJECTS = $(am_test_ftp_OBJECTS) test_ftp_LDADD = $(LDADD) test_ftp_DEPENDENCIES = $(top_builddir)/src/ulib/lib@ULIB@.la +am_test_hash_map_OBJECTS = test_hash_map.$(OBJEXT) +test_hash_map_OBJECTS = $(am_test_hash_map_OBJECTS) +test_hash_map_LDADD = $(LDADD) +test_hash_map_DEPENDENCIES = $(top_builddir)/src/ulib/lib@ULIB@.la am_test_header_OBJECTS = test_header.$(OBJEXT) test_header_OBJECTS = $(am_test_header_OBJECTS) test_header_LDADD = $(LDADD) @@ -608,28 +612,29 @@ SOURCES = $(product1_la_SOURCES) $(product2_la_SOURCES) \ $(test_entity_SOURCES) $(test_event_SOURCES) \ $(test_expat_SOURCES) $(test_file_SOURCES) \ $(test_file_config_SOURCES) $(test_ftp_SOURCES) \ - $(test_header_SOURCES) $(test_http_SOURCES) \ - $(test_https_SOURCES) $(test_imap_SOURCES) \ - $(test_interrupt_SOURCES) $(test_ipaddress_SOURCES) \ - $(test_json_SOURCES) $(test_ldap_SOURCES) $(test_log_SOURCES) \ - $(test_magic_SOURCES) $(test_memory_pool_SOURCES) \ - $(test_mongodb_SOURCES) $(test_multipart_SOURCES) \ - $(test_notifier_SOURCES) $(test_options_SOURCES) \ - $(test_orm_SOURCES) $(test_pcre_SOURCES) \ - $(test_pkcs10_SOURCES) $(test_pkcs7_SOURCES) \ - $(test_plugin_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_hash_map_SOURCES) $(test_header_SOURCES) \ + $(test_http_SOURCES) $(test_https_SOURCES) \ + $(test_imap_SOURCES) $(test_interrupt_SOURCES) \ + $(test_ipaddress_SOURCES) $(test_json_SOURCES) \ + $(test_ldap_SOURCES) $(test_log_SOURCES) $(test_magic_SOURCES) \ + $(test_memory_pool_SOURCES) $(test_mongodb_SOURCES) \ + $(test_multipart_SOURCES) $(test_notifier_SOURCES) \ + $(test_options_SOURCES) $(test_orm_SOURCES) \ + $(test_pcre_SOURCES) $(test_pkcs10_SOURCES) \ + $(test_pkcs7_SOURCES) $(test_plugin_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_unixsocket_server_SOURCES) $(test_url_SOURCES) \ $(test_vector_SOURCES) $(test_zip_SOURCES) DIST_SOURCES = $(am__product1_la_SOURCES_DIST) \ @@ -645,11 +650,12 @@ DIST_SOURCES = $(am__product1_la_SOURCES_DIST) \ $(test_entity_SOURCES) $(am__test_event_SOURCES_DIST) \ $(am__test_expat_SOURCES_DIST) $(test_file_SOURCES) \ $(test_file_config_SOURCES) $(test_ftp_SOURCES) \ - $(test_header_SOURCES) $(test_http_SOURCES) \ - $(am__test_https_SOURCES_DIST) $(test_imap_SOURCES) \ - $(am__test_interrupt_SOURCES_DIST) $(test_ipaddress_SOURCES) \ - $(test_json_SOURCES) $(am__test_ldap_SOURCES_DIST) \ - $(test_log_SOURCES) $(am__test_magic_SOURCES_DIST) \ + $(test_hash_map_SOURCES) $(test_header_SOURCES) \ + $(test_http_SOURCES) $(am__test_https_SOURCES_DIST) \ + $(test_imap_SOURCES) $(am__test_interrupt_SOURCES_DIST) \ + $(test_ipaddress_SOURCES) $(test_json_SOURCES) \ + $(am__test_ldap_SOURCES_DIST) $(test_log_SOURCES) \ + $(am__test_magic_SOURCES_DIST) \ $(am__test_memory_pool_SOURCES_DIST) $(test_mongodb_SOURCES) \ $(test_multipart_SOURCES) $(test_notifier_SOURCES) \ $(test_options_SOURCES) $(am__test_orm_SOURCES_DIST) \ @@ -1111,7 +1117,7 @@ PRG = test_timeval test_timer test_notifier test_string test_file \ 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_elasticsearch test_smtp test_pop3 test_imap test_hash_map \ $(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) \ @@ -1125,12 +1131,12 @@ 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 $(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 $(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) @@ -1179,6 +1185,7 @@ test_server_SOURCES = test_server.cpp 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 @PTHREAD_TRUE@test_thread_SOURCES = test_thread.cpp @ZIP_TRUE@test_zip_SOURCES = test_zip.cpp @LIBTDB_TRUE@test_tdb_SOURCES = test_tdb.cpp @@ -1375,6 +1382,10 @@ test_ftp$(EXEEXT): $(test_ftp_OBJECTS) $(test_ftp_DEPENDENCIES) $(EXTRA_test_ftp @rm -f test_ftp$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(test_ftp_OBJECTS) $(test_ftp_LDADD) $(LIBS) +test_hash_map$(EXEEXT): $(test_hash_map_OBJECTS) $(test_hash_map_DEPENDENCIES) $(EXTRA_test_hash_map_DEPENDENCIES) + @rm -f test_hash_map$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(test_hash_map_OBJECTS) $(test_hash_map_LDADD) $(LIBS) + test_header$(EXEEXT): $(test_header_OBJECTS) $(test_header_DEPENDENCIES) $(EXTRA_test_header_DEPENDENCIES) @rm -f test_header$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(test_header_OBJECTS) $(test_header_LDADD) $(LIBS) @@ -1602,6 +1613,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_file.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_file_config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ftp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_hash_map.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_header.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_http.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_https.Po@am__quote@ @@ -2065,7 +2077,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 ../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 ../reset.color clean-local: -rm -rf out err core .libs *.bb* *.da *.gc* *.log test_log.log* tmp/* \ diff --git a/tests/ulib/hash_map.test b/tests/ulib/hash_map.test new file mode 100755 index 00000000..7d3531bf --- /dev/null +++ b/tests/ulib/hash_map.test @@ -0,0 +1,19 @@ +#!/bin/sh + +. ../.function + +## hash_map.test -- Test hash_map feature + +start_msg hash_map + +#UTRACE="0 10M 0" +#UOBJDUMP="0 100k 10" +#USIMERR="error.sim" + export UTRACE UOBJDUMP USIMERR + +#STRACE=$LTRUSS +#VALGRIND=valgrind +start_prg hash_map 60 CHECK_QUOTING -> str = "Manager of my caz"... LDAP_SERVER_ADDRESS -> 10.10.15.1:389 LDAP_SERVER_ADDRESS_MAIL -> 10.10.15.1:389 -LOG_FILE -> ldap_update.log +MAILDELIVERYOPTION -> mailbox +MAILHOST -> mailsrv.bf.bnl.it +MESSAGE_QUEUE_MANAGER -> frontend +MESSAGE_QUEUE_SERVER -> JAVA.CHANNEL/TCP/lobelia(1414) PASSWORD -> secret PASSWORD_MAIL -> secret -ROOT_DN -> o=BNL,c=IT ROOT_DN_MAIL -> ou=Utenti,ou=e-family.it,o=BNL,c=IT -TIME_SLEEP_MQSERIES_ERROR -> 60 --------------------------- # Time Consumed with num_iteration(100) = 0 ms diff --git a/tests/ulib/ok/hash_map.ok b/tests/ulib/ok/hash_map.ok new file mode 100644 index 00000000..4f4d43ac --- /dev/null +++ b/tests/ulib/ok/hash_map.ok @@ -0,0 +1,75 @@ +[ +FILE_WRONG_MESSAGE ldap_update.wrg +MAILHOST mailsrv.bf.bnl.it +PASSWORD_MAIL secret +ADMIN_DN_MAIL cn=Manager,o=BNL,c=IT +ROOT_DN o=BNL,c=IT +MESSAGE_QUEUE_MANAGER frontend +LDAP_SERVER_ADDRESS 10.10.15.1:389 +ADMIN_DN cn=Manager,o=BNL,c=IT +ROOT_DN_MAIL ou=Utenti,ou=e-family.it,o=BNL,c=IT +PASSWORD secret +MAX_ERROR_FOR_CONNECT 2 +MESSAGE_QUEUE_SERVER JAVA.CHANNEL/TCP/lobelia(1414) +LOG_FILE ldap_update.log +CHECK_QUOTING "str = \"Manager of my caz\"..." +MAILDELIVERYOPTION mailbox +TIME_SLEEP_LDAP_ERROR 10 +LDAP_SERVER_ADDRESS_MAIL 10.10.15.1:389 +TIME_SLEEP_MQSERIES_ERROR 60 +MESSAGE_QUEUE_NAME LDAP.UPDATE.QUEUE +] +[ +FILE_WRONG_MESSAGE ldap_update.wrg +MAILHOST mailsrv.bf.bnl.it +PASSWORD_MAIL secret +ADMIN_DN_MAIL cn=Manager,o=BNL,c=IT +ROOT_DN o=BNL,c=IT +MESSAGE_QUEUE_MANAGER frontend +LDAP_SERVER_ADDRESS 10.10.15.1:389 +ADMIN_DN cn=Manager,o=BNL,c=IT +ROOT_DN_MAIL ou=Utenti,ou=e-family.it,o=BNL,c=IT +PASSWORD secret +MAX_ERROR_FOR_CONNECT 2 +MESSAGE_QUEUE_SERVER JAVA.CHANNEL/TCP/lobelia(1414) +LOG_FILE ldap_update.log +CHECK_QUOTING "str = \"Manager of my caz\"..." +MAILDELIVERYOPTION mailbox +TIME_SLEEP_LDAP_ERROR 10 +LDAP_SERVER_ADDRESS_MAIL 10.10.15.1:389 +TIME_SLEEP_MQSERIES_ERROR 60 +MESSAGE_QUEUE_NAME LDAP.UPDATE.QUEUE +] +--------------------------- +ADMIN_DN -> cn=Manager,o=BNL,c=IT +ADMIN_DN_MAIL -> cn=Manager,o=BNL,c=IT +CHECK_QUOTING -> str = "Manager of my caz"... +FILE_WRONG_MESSAGE -> ldap_update.wrg +LDAP_SERVER_ADDRESS -> 10.10.15.1:389 +LDAP_SERVER_ADDRESS_MAIL -> 10.10.15.1:389 +LOG_FILE -> ldap_update.log +MAILDELIVERYOPTION -> mailbox +MAILHOST -> mailsrv.bf.bnl.it +MAX_ERROR_FOR_CONNECT -> 2 +MESSAGE_QUEUE_MANAGER -> frontend +MESSAGE_QUEUE_NAME -> LDAP.UPDATE.QUEUE +MESSAGE_QUEUE_SERVER -> JAVA.CHANNEL/TCP/lobelia(1414) +PASSWORD -> secret +PASSWORD_MAIL -> secret +ROOT_DN -> o=BNL,c=IT +ROOT_DN_MAIL -> ou=Utenti,ou=e-family.it,o=BNL,c=IT +TIME_SLEEP_LDAP_ERROR -> 10 +TIME_SLEEP_MQSERIES_ERROR -> 60 +--------------------------- +ADMIN_DN_MAIL -> cn=Manager,o=BNL,c=IT +LDAP_SERVER_ADDRESS -> 10.10.15.1:389 +LDAP_SERVER_ADDRESS_MAIL -> 10.10.15.1:389 +LOG_FILE -> ldap_update.log +MAILDELIVERYOPTION -> mailbox +MAILHOST -> mailsrv.bf.bnl.it +MESSAGE_QUEUE_NAME -> LDAP.UPDATE.QUEUE +MESSAGE_QUEUE_SERVER -> JAVA.CHANNEL/TCP/lobelia(1414) +PASSWORD -> secret +ROOT_DN -> o=BNL,c=IT +ROOT_DN_MAIL -> ou=Utenti,ou=e-family.it,o=BNL,c=IT +--------------------------- \ No newline at end of file diff --git a/tests/ulib/test_file.cpp b/tests/ulib/test_file.cpp index af7ba5e8..f878c205 100644 --- a/tests/ulib/test_file.cpp +++ b/tests/ulib/test_file.cpp @@ -95,37 +95,37 @@ U_EXPORT main (int argc, char* argv[]) #ifndef __MINGW32__ buffer.assign(argv[1]); - x.setPath(U_STRING_FROM_CONSTANT("~")); + x.setPath(U_STRING_FROM_CONSTANT("~"), U_NULLPTR); U_ASSERT( x.getPath() == buffer ) buffer.push_back('/'); - x.setPath(U_STRING_FROM_CONSTANT("~/")); + x.setPath(U_STRING_FROM_CONSTANT("~/"), U_NULLPTR); U_ASSERT( x.getPath() == buffer ) buffer.assign(argv[2]); - x.setPath(U_STRING_FROM_CONSTANT("~root/")); + x.setPath(U_STRING_FROM_CONSTANT("~root/"), U_NULLPTR); U_ASSERT( x.getPath() == buffer ) buffer.assign(argv[1]); buffer.append("/.bash_profile"); - x.setPath(U_STRING_FROM_CONSTANT("~/.bash_profile")); + x.setPath(U_STRING_FROM_CONSTANT("~/.bash_profile"), U_NULLPTR); U_ASSERT( x.getPath() == buffer ) buffer.assign(argv[2]); buffer.append(".bash_profile"); - x.setPath(U_STRING_FROM_CONSTANT("~root/.bash_profile")); + x.setPath(U_STRING_FROM_CONSTANT("~root/.bash_profile"), U_NULLPTR); U_ASSERT( x.getPath() == buffer ) buffer.assign(argv[3]); - x.setPath(U_STRING_FROM_CONSTANT("$PWD")); + x.setPath(U_STRING_FROM_CONSTANT("$PWD"), U_NULLPTR); U_ASSERT( x.getPath() == buffer ) buffer.append("/"); - x.setPath(U_STRING_FROM_CONSTANT("$PWD/")); + x.setPath(U_STRING_FROM_CONSTANT("$PWD/"), U_NULLPTR); U_ASSERT( x.getPath() == buffer ) buffer.append("test_file.cpp"); - x.setPath(U_STRING_FROM_CONSTANT("$PWD/test_file.cpp")); + x.setPath(U_STRING_FROM_CONSTANT("$PWD/test_file.cpp"), U_NULLPTR); U_ASSERT( x.getPath() == buffer ) #endif diff --git a/tests/ulib/test_file_config.cpp b/tests/ulib/test_file_config.cpp index f74ea7c0..55fdd8a9 100644 --- a/tests/ulib/test_file_config.cpp +++ b/tests/ulib/test_file_config.cpp @@ -6,21 +6,21 @@ #include extern "C" { -# include "file_config.gperf" +#include "file_config.gperf" } -static bool setIndex(UHashMap* pthis, const char* p, uint32_t sz) +static bool setIndex(UHashMap* pthis) { - U_TRACE(5, "setIndex(%p,%.*S,%u)", pthis, sz, p, sz) + U_TRACE(5, "setIndex(%p)", pthis) - pthis->index = gperf_hash(p, sz); + UHashMap::index = (UHashMap::lhash = gperf_hash(U_STRING_TO_PARAM(*UHashMap::lkey))) & pthis->getMask(); U_RETURN(false); } static void check(UFileConfig& y) { - U_TRACE(5,"check()") + U_TRACE_NO_PARAM(5, "check()") U_ASSERT( y[U_STRING_FROM_CONSTANT("LOG_FILE")] == U_STRING_FROM_CONSTANT("ldap_update.log") ) U_ASSERT( y[U_STRING_FROM_CONSTANT("LDAP_SERVER_ADDRESS")] == U_STRING_FROM_CONSTANT("10.10.15.1:389") ) @@ -45,37 +45,35 @@ static void check(UFileConfig& y) static void check1(UFileConfig& y) { - U_TRACE(5,"check1()") - -// y.table.reserve(y.table.capacity() * 2); + U_TRACE_NO_PARAM(5, "check1()") UString value = y.erase(U_STRING_FROM_CONSTANT("LDAP_SERVER_ADDRESS")); U_ASSERT( value == U_STRING_FROM_CONSTANT("10.10.15.1:389") ) - U_ASSERT( y[U_STRING_FROM_CONSTANT("LDAP_SERVER_ADDRESS")] == U_STRING_FROM_CONSTANT("") ) + U_ASSERT( y[U_STRING_FROM_CONSTANT("LDAP_SERVER_ADDRESS")] == UString::getStringNull() ) U_ASSERT( y.erase(U_STRING_FROM_CONSTANT("ROOT_DN")) == U_STRING_FROM_CONSTANT("o=BNL,c=IT") ) - U_ASSERT( y[U_STRING_FROM_CONSTANT("ROOT_DN")] == U_STRING_FROM_CONSTANT("") ) + U_ASSERT( y[U_STRING_FROM_CONSTANT("ROOT_DN")] == UString::getStringNull() ) U_ASSERT( y.erase(U_STRING_FROM_CONSTANT("ADMIN_DN")) == U_STRING_FROM_CONSTANT("cn=Manager,o=BNL,c=IT") ) - U_ASSERT( y[U_STRING_FROM_CONSTANT("ADMIN_DN")] == U_STRING_FROM_CONSTANT("") ) + U_ASSERT( y[U_STRING_FROM_CONSTANT("ADMIN_DN")] == UString::getStringNull() ) y.table.clear(); U_ASSERT( y.empty() == true ) - U_ASSERT( y[U_STRING_FROM_CONSTANT("TIME_SLEEP_MQSERIES_ERROR")] == U_STRING_FROM_CONSTANT("") ) + U_ASSERT( y[U_STRING_FROM_CONSTANT("TIME_SLEEP_MQSERIES_ERROR")] == UString::getStringNull() ) } static void check2(UFileConfig& y) { - U_TRACE(5,"check2()") + U_TRACE_NO_PARAM(5, "check2()") - U_ASSERT( y.erase(U_STRING_FROM_CONSTANT("NOT_PRESENT")) == U_STRING_FROM_CONSTANT("") ) - U_ASSERT( y[U_STRING_FROM_CONSTANT("NOT_PRESENT")] == U_STRING_FROM_CONSTANT("") ) + U_ASSERT( y.erase(U_STRING_FROM_CONSTANT("NOT_PRESENT")) == UString::getStringNull() ) + U_ASSERT( y[U_STRING_FROM_CONSTANT("NOT_PRESENT")] == UString::getStringNull() ) - y.table.insertAfterFind(U_STRING_FROM_CONSTANT("NOT_PRESENT"), U_STRING_FROM_CONSTANT("60M")); + y.table.insert(U_STRING_FROM_CONSTANT("NOT_PRESENT"), U_STRING_FROM_CONSTANT("60M")); - U_ASSERT( y[U_STRING_FROM_CONSTANT("NOT_PRESENT")] == U_STRING_FROM_CONSTANT("60M") ) + U_ASSERT( y[U_STRING_FROM_CONSTANT("NOT_PRESENT")] == U_STRING_FROM_CONSTANT("60M") ) UString value = y[U_STRING_FROM_CONSTANT("NOT_PRESENT")]; @@ -110,72 +108,6 @@ static bool cancella(UStringRep* key, void* value) U_RETURN(false); } -#if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX14) -class MessageDelivery { -public: - int64_t messageDateTime; - - MessageDelivery() { messageDateTime = 0; } -}; - -typedef UVector vmsg; -#endif - -static void testHashMapIterator() -{ - U_TRACE_NO_PARAM(5, "testHashMapIterator()") - -#if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX14) - UVector badUsers; - UHashMap deliveries; - int64_t twentyFourHoursAgoInMilliseconds = 1; - - auto badUserMapCleaner = [&] (UHashMapNode*& node) -> bool - { - for (UString badUser : badUsers) - { - if (badUser.rep->equal(node->key)) return true; - } - - return false; - }; - - UHashMapAnonIter it = deliveries.begin(); - - while (it != deliveries.end()) - { - UHashMapNode* node = *it; - - // remove expired users - if (badUsers.size() && badUserMapCleaner(node)) - { - it = deliveries.erase(it); - - continue; - } - - ++it; - - // remove expired deliveries - - unsigned a = 0; - vmsg* vdeliveries = (vmsg*)node->elem; - - while (a < vdeliveries->size()) - { - if (vdeliveries->at(a)->messageDateTime < twentyFourHoursAgoInMilliseconds) - { - vdeliveries->erase(a); - - continue; - } - - a++; - } - } -#endif -} - int U_EXPORT main (int argc, char* argv[], char* env[]) { U_ULIB_INIT(argv); @@ -188,8 +120,7 @@ int U_EXPORT main (int argc, char* argv[], char* env[]) y.destroy(); y.table.setIndexFunction(setIndex); - - y.table.allocate(MAX_HASH_VALUE+1); + y.table.allocate(64); y.load(U_STRING_FROM_CONSTANT("file_config.cf")); @@ -236,6 +167,8 @@ int U_EXPORT main (int argc, char* argv[], char* env[]) x.clear(); + U_ASSERT( y.table.invariant() ) + // Time Consumed with num_iteration(10) = 543 ms n = (argc > 1 ? u_atoi(argv[1]) : 5); diff --git a/tests/ulib/test_hash_map.cpp b/tests/ulib/test_hash_map.cpp new file mode 100644 index 00000000..b94e9b5c --- /dev/null +++ b/tests/ulib/test_hash_map.cpp @@ -0,0 +1,236 @@ +// test_hash_map.cpp + +#include +#include + +#include + +extern "C" { +#include "file_config.gperf" +} + +static bool setIndex(UHashMap* pthis) +{ + U_TRACE(5, "setIndex(%p)", pthis) + + UHashMap::index = (UHashMap::lhash = gperf_hash(U_STRING_TO_PARAM(*UHashMap::lkey))) & pthis->getMask(); + + U_RETURN(false); +} + +static void check0(UHashMap& y) +{ + U_TRACE_NO_PARAM(5, "check0()") + + U_ASSERT( y.invariant() ) + + U_ASSERT( y["LOG_FILE"] == U_STRING_FROM_CONSTANT("ldap_update.log") ) + U_ASSERT( y["LDAP_SERVER_ADDRESS"] == U_STRING_FROM_CONSTANT("10.10.15.1:389") ) + U_ASSERT( y["ROOT_DN"] == U_STRING_FROM_CONSTANT("o=BNL,c=IT") ) + U_ASSERT( y["ADMIN_DN"] == U_STRING_FROM_CONSTANT("cn=Manager,o=BNL,c=IT") ) + U_ASSERT( y["PASSWORD"] == U_STRING_FROM_CONSTANT("secret") ) + U_ASSERT( y["LDAP_SERVER_ADDRESS_MAIL"] == U_STRING_FROM_CONSTANT("10.10.15.1:389") ) + U_ASSERT( y["ROOT_DN_MAIL"] == U_STRING_FROM_CONSTANT("ou=Utenti,ou=e-family.it,o=BNL,c=IT") ) + U_ASSERT( y["ADMIN_DN_MAIL"] == U_STRING_FROM_CONSTANT("cn=Manager,o=BNL,c=IT") ) + U_ASSERT( y["PASSWORD_MAIL"] == U_STRING_FROM_CONSTANT("secret") ) + U_ASSERT( y["MAILHOST"] == U_STRING_FROM_CONSTANT("mailsrv.bf.bnl.it") ) + U_ASSERT( y["MAILDELIVERYOPTION"] == U_STRING_FROM_CONSTANT("mailbox") ) + U_ASSERT( y["FILE_WRONG_MESSAGE"] == U_STRING_FROM_CONSTANT("ldap_update.wrg") ) + U_ASSERT( y["MESSAGE_QUEUE_NAME"] == U_STRING_FROM_CONSTANT("LDAP.UPDATE.QUEUE") ) + U_ASSERT( y["MESSAGE_QUEUE_SERVER"] == U_STRING_FROM_CONSTANT("JAVA.CHANNEL/TCP/lobelia(1414)") ) + U_ASSERT( y["MESSAGE_QUEUE_MANAGER"] == U_STRING_FROM_CONSTANT("frontend") ) + U_ASSERT( y["MAX_ERROR_FOR_CONNECT"] == U_STRING_FROM_CONSTANT("2") ) + U_ASSERT( y["TIME_SLEEP_LDAP_ERROR"] == U_STRING_FROM_CONSTANT("10") ) + U_ASSERT( y["TIME_SLEEP_MQSERIES_ERROR"] == U_STRING_FROM_CONSTANT("60") ) + U_ASSERT( y["CHECK_QUOTING"] == U_STRING_FROM_CONSTANT("str = \"Manager of my caz\"...") ) +} + +static void check1(UHashMap& y) +{ + U_TRACE_NO_PARAM(5, "check1()") + + U_ASSERT( y.invariant() ) + + UString value = y.erase(U_STRING_FROM_CONSTANT("LDAP_SERVER_ADDRESS")); + + U_ASSERT( y["LDAP_SERVER_ADDRESS"] == UString::getStringNull() ) + U_ASSERT( value == U_STRING_FROM_CONSTANT("10.10.15.1:389") ) + + U_ASSERT( y.erase(U_STRING_FROM_CONSTANT("ROOT_DN")) == U_STRING_FROM_CONSTANT("o=BNL,c=IT") ) + U_ASSERT( y[U_STRING_FROM_CONSTANT("ROOT_DN")] == UString::getStringNull() ) + + U_ASSERT( y.erase(U_STRING_FROM_CONSTANT("ADMIN_DN")) == U_STRING_FROM_CONSTANT("cn=Manager,o=BNL,c=IT") ) + U_ASSERT( y[U_STRING_FROM_CONSTANT("ADMIN_DN")] == UString::getStringNull() ) + + y.clear(); + + U_ASSERT( y.empty() ) + U_ASSERT( y[U_STRING_FROM_CONSTANT("TIME_SLEEP_MQSERIES_ERROR")] == UString::getStringNull() ) +} + +static void check2(UHashMap& y) +{ + U_TRACE_NO_PARAM(5, "check2()") + + U_ASSERT( y.erase(U_STRING_FROM_CONSTANT("NOT_PRESENT")) == UString::getStringNull() ) + U_ASSERT( y[ "NOT_PRESENT"] == UString::getStringNull() ) + + y.insertAfterFind(U_STRING_FROM_CONSTANT("60M")); + + U_ASSERT( y["NOT_PRESENT"] == U_STRING_FROM_CONSTANT("60M") ) + + UString value = y["NOT_PRESENT"]; + + U_ASSERT( y.erase(U_STRING_FROM_CONSTANT("NOT_PRESENT")) == U_STRING_FROM_CONSTANT("60M") ) + + U_ASSERT( value == U_STRING_FROM_CONSTANT("60M") ) + + U_ASSERT( value.strtoul(true) == 60 * 1024 * 1024 ) + U_ASSERT( value.strtoull(true) == 60LL * 1024LL * 1024LL ) +} + +static void print(UStringRep* key, void* value) +{ + U_TRACE(5, "print(%V,%p)", key, value) + + cout << '\n'; + cout.write(key->data(), key->size()); + cout << " -> "; + cout.write(((UStringRep*)value)->data(), ((UStringRep*)value)->size()); +} + +static bool cancella(UStringRep* key, void* value) +{ + U_TRACE(5, "cancella(%V,%p)", key, value) + + static int cnt; + + if (++cnt & 1) U_RETURN(true); + + U_RETURN(false); +} + +#if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX14) +class MessageDelivery { +public: + int64_t messageDateTime; + + MessageDelivery() { messageDateTime = 0; } +}; + +typedef UVector vmsg; +#endif + +static void testHashMapIterator() +{ + U_TRACE_NO_PARAM(5, "testHashMapIterator()") + +#if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX14) + UVector badUsers; + UHashMap deliveries; + int64_t twentyFourHoursAgoInMilliseconds = 1; + + auto badUserMapCleaner = [&] (UHashMapNode*& node) -> bool + { + for (UString badUser : badUsers) + { + if (badUser.rep->equal(node->key)) return true; + } + + return false; + }; + + UHashMapAnonIter it = deliveries.begin(); + + while (it != deliveries.end()) + { + UHashMapNode* node = *it; + + // remove expired users + + if (badUsers.size() && + badUserMapCleaner(node)) + { + it = deliveries.erase(it); + + continue; + } + + ++it; + + // remove expired deliveries + + unsigned a = 0; + vmsg* vdeliveries = (vmsg*)node->elem; + + while (a < vdeliveries->size()) + { + if (vdeliveries->at(a)->messageDateTime < twentyFourHoursAgoInMilliseconds) + { + vdeliveries->erase(a); + + continue; + } + + a++; + } + } +#endif +} + +int U_EXPORT main(int argc, char* argv[], char* env[]) +{ + U_ULIB_INIT(argv); + + U_TRACE(5, "main(%d)", argc) + + UHashMap table(16, setIndex), z, x; + + table.loadFromData(UFile::contentOf(U_STRING_FROM_CONSTANT("file_config.cf"))); + + U_ASSERT( table.size() == TOTAL_KEYWORDS+1 ) + + uint32_t n = table.first(); + + while (table.next()) ++n; + + U_ASSERT( n == TOTAL_KEYWORDS+1 ) + + check0(table); + check1(table); + + table.setIgnoreCase(false); + + cin >> table; + cout << table; + + z.assign(table); + + cout << "\n" << z; + + x.assign(z); + + cout << "\n---------------------------"; + z.callForAllEntrySorted(print); + z.callWithDeleteForAllEntry(cancella); + cout << "\n---------------------------"; + z.callForAllEntrySorted(print); + cout << "\n---------------------------"; + + z.clear(); + + check1(table); + check2(table); + + table.assign(x); + + x.clear(); + + 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, 609) + + U_ASSERT( table.invariant() ) +} diff --git a/tests/ulib/test_string.cpp b/tests/ulib/test_string.cpp index f9b14d59..6a319429 100644 --- a/tests/ulib/test_string.cpp +++ b/tests/ulib/test_string.cpp @@ -1503,6 +1503,9 @@ U_EXPORT main(int argc, char* argv[]) /* double val1 = U_STRING_FROM_CONSTANT("0").strtod(); u__printf(1, U_CONSTANT_TO_PARAM("0 = %lf %g"), val1, val1); + UString data = U_STRING_FROM_CONSTANT("0$&$&$&$&$&$&$&$&$&$&fileName"); + UVector vec(data, "$&$&$"); + for (auto part : vec) cout << "part = " << part << '\n'; exit(0); */