summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime/common/string
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-03-26 19:21:20 +0000
committer <>2014-05-08 15:03:54 +0000
commitfb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch)
treec2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Runtime/common/string
parent58ed4748338f9466599adfc8a9171280ed99e23f (diff)
downloadVirtualBox-master.tar.gz
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Runtime/common/string')
-rw-r--r--src/VBox/Runtime/common/string/RTStrCmp.cpp2
-rw-r--r--src/VBox/Runtime/common/string/RTStrNCmp.cpp17
-rw-r--r--src/VBox/Runtime/common/string/RTStrNLen.cpp2
-rw-r--r--src/VBox/Runtime/common/string/RTStrNLenEx.cpp2
-rw-r--r--src/VBox/Runtime/common/string/RTStrPrintHexBytes.cpp2
-rw-r--r--src/VBox/Runtime/common/string/RTStrStr.cpp2
-rw-r--r--src/VBox/Runtime/common/string/base64.cpp2
-rw-r--r--src/VBox/Runtime/common/string/memchr.asm2
-rw-r--r--src/VBox/Runtime/common/string/memchr.cpp2
-rw-r--r--src/VBox/Runtime/common/string/memchr_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/memcmp.asm2
-rw-r--r--src/VBox/Runtime/common/string/memcmp.cpp2
-rw-r--r--src/VBox/Runtime/common/string/memcmp_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/memcpy.asm2
-rw-r--r--src/VBox/Runtime/common/string/memcpy.cpp2
-rw-r--r--src/VBox/Runtime/common/string/memcpy_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/memmove.asm2
-rw-r--r--src/VBox/Runtime/common/string/memmove_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/mempcpy.asm2
-rw-r--r--src/VBox/Runtime/common/string/memset.asm2
-rw-r--r--src/VBox/Runtime/common/string/memset.cpp2
-rw-r--r--src/VBox/Runtime/common/string/memset_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/simplepattern.cpp2
-rw-r--r--src/VBox/Runtime/common/string/straprintf.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strcache.cpp1163
-rw-r--r--src/VBox/Runtime/common/string/strchr.asm2
-rw-r--r--src/VBox/Runtime/common/string/strchr_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/strcmp.asm2
-rw-r--r--src/VBox/Runtime/common/string/strcmp_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/strcpy.asm2
-rw-r--r--src/VBox/Runtime/common/string/strcpy.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strcpy_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/strformat.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strformatnum.cpp4
-rw-r--r--src/VBox/Runtime/common/string/strformatrt.cpp189
-rw-r--r--src/VBox/Runtime/common/string/strformattype.cpp6
-rw-r--r--src/VBox/Runtime/common/string/strlen.asm2
-rw-r--r--src/VBox/Runtime/common/string/strlen.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strlen_alias.c2
-rw-r--r--src/VBox/Runtime/common/string/strncmp.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strpbrk.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strprintf.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strspace.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strstrip.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strtonum.cpp2
-rw-r--r--src/VBox/Runtime/common/string/strversion.cpp2
-rw-r--r--src/VBox/Runtime/common/string/uni.cpp2
-rw-r--r--src/VBox/Runtime/common/string/unidata.cpp2
-rw-r--r--src/VBox/Runtime/common/string/uniread.cpp4
-rw-r--r--src/VBox/Runtime/common/string/utf-16.cpp2
-rw-r--r--src/VBox/Runtime/common/string/utf-8-case.cpp79
-rw-r--r--src/VBox/Runtime/common/string/utf-8.cpp2
52 files changed, 1372 insertions, 180 deletions
diff --git a/src/VBox/Runtime/common/string/RTStrCmp.cpp b/src/VBox/Runtime/common/string/RTStrCmp.cpp
index 779675f0..598a1869 100644
--- a/src/VBox/Runtime/common/string/RTStrCmp.cpp
+++ b/src/VBox/Runtime/common/string/RTStrCmp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/RTStrNCmp.cpp b/src/VBox/Runtime/common/string/RTStrNCmp.cpp
index 5070218a..5880c8ff 100644
--- a/src/VBox/Runtime/common/string/RTStrNCmp.cpp
+++ b/src/VBox/Runtime/common/string/RTStrNCmp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -41,7 +41,22 @@ RTDECL(int) RTStrNCmp(const char *psz1, const char *psz2, size_t cchMax)
if (!psz2)
return 1;
+#ifdef RT_OS_SOLARIS
+ /* Solaris: tstUtf8 found to fail for some RTSTR_MAX on testboxsh1:
+ solaris.amd64 v5.10 (Generic_142901-12 (Assembled 30 March 2009)). */
+ while (cchMax-- > 0)
+ {
+ char ch1 = *psz1++;
+ char ch2 = *psz2++;
+ if (ch1 != ch2)
+ return ch1 > ch2 ? 1 : -1;
+ else if (ch1 == 0)
+ break;
+ }
+ return 0;
+#else
return strncmp(psz1, psz2, cchMax);
+#endif
}
RT_EXPORT_SYMBOL(RTStrNCmp);
diff --git a/src/VBox/Runtime/common/string/RTStrNLen.cpp b/src/VBox/Runtime/common/string/RTStrNLen.cpp
index d30c9ed5..777c7509 100644
--- a/src/VBox/Runtime/common/string/RTStrNLen.cpp
+++ b/src/VBox/Runtime/common/string/RTStrNLen.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/RTStrNLenEx.cpp b/src/VBox/Runtime/common/string/RTStrNLenEx.cpp
index 3764ce35..19e18152 100644
--- a/src/VBox/Runtime/common/string/RTStrNLenEx.cpp
+++ b/src/VBox/Runtime/common/string/RTStrNLenEx.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/RTStrPrintHexBytes.cpp b/src/VBox/Runtime/common/string/RTStrPrintHexBytes.cpp
index f00298e5..492f2f49 100644
--- a/src/VBox/Runtime/common/string/RTStrPrintHexBytes.cpp
+++ b/src/VBox/Runtime/common/string/RTStrPrintHexBytes.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/RTStrStr.cpp b/src/VBox/Runtime/common/string/RTStrStr.cpp
index 903826e1..a6555bf5 100644
--- a/src/VBox/Runtime/common/string/RTStrStr.cpp
+++ b/src/VBox/Runtime/common/string/RTStrStr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/base64.cpp b/src/VBox/Runtime/common/string/base64.cpp
index 514d4474..96269644 100644
--- a/src/VBox/Runtime/common/string/base64.cpp
+++ b/src/VBox/Runtime/common/string/base64.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memchr.asm b/src/VBox/Runtime/common/string/memchr.asm
index 0ee2968d..95fd1654 100644
--- a/src/VBox/Runtime/common/string/memchr.asm
+++ b/src/VBox/Runtime/common/string/memchr.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memchr.cpp b/src/VBox/Runtime/common/string/memchr.cpp
index ba2de095..abfa379d 100644
--- a/src/VBox/Runtime/common/string/memchr.cpp
+++ b/src/VBox/Runtime/common/string/memchr.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memchr_alias.c b/src/VBox/Runtime/common/string/memchr_alias.c
index 0d009c7d..90929549 100644
--- a/src/VBox/Runtime/common/string/memchr_alias.c
+++ b/src/VBox/Runtime/common/string/memchr_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memcmp.asm b/src/VBox/Runtime/common/string/memcmp.asm
index afadf923..5176dfed 100644
--- a/src/VBox/Runtime/common/string/memcmp.asm
+++ b/src/VBox/Runtime/common/string/memcmp.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memcmp.cpp b/src/VBox/Runtime/common/string/memcmp.cpp
index 3dea769e..6ccf9b1f 100644
--- a/src/VBox/Runtime/common/string/memcmp.cpp
+++ b/src/VBox/Runtime/common/string/memcmp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memcmp_alias.c b/src/VBox/Runtime/common/string/memcmp_alias.c
index 30f78637..6a4337b8 100644
--- a/src/VBox/Runtime/common/string/memcmp_alias.c
+++ b/src/VBox/Runtime/common/string/memcmp_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memcpy.asm b/src/VBox/Runtime/common/string/memcpy.asm
index 6f1bed22..b8f94df5 100644
--- a/src/VBox/Runtime/common/string/memcpy.asm
+++ b/src/VBox/Runtime/common/string/memcpy.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memcpy.cpp b/src/VBox/Runtime/common/string/memcpy.cpp
index 56ccdfb2..d04cfe04 100644
--- a/src/VBox/Runtime/common/string/memcpy.cpp
+++ b/src/VBox/Runtime/common/string/memcpy.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memcpy_alias.c b/src/VBox/Runtime/common/string/memcpy_alias.c
index 5ddc7b8c..ecea9ae3 100644
--- a/src/VBox/Runtime/common/string/memcpy_alias.c
+++ b/src/VBox/Runtime/common/string/memcpy_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memmove.asm b/src/VBox/Runtime/common/string/memmove.asm
index b10ede77..c52d988e 100644
--- a/src/VBox/Runtime/common/string/memmove.asm
+++ b/src/VBox/Runtime/common/string/memmove.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2008 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memmove_alias.c b/src/VBox/Runtime/common/string/memmove_alias.c
index f30c9149..1fc2e0ce 100644
--- a/src/VBox/Runtime/common/string/memmove_alias.c
+++ b/src/VBox/Runtime/common/string/memmove_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/mempcpy.asm b/src/VBox/Runtime/common/string/mempcpy.asm
index b47c4368..157a63db 100644
--- a/src/VBox/Runtime/common/string/mempcpy.asm
+++ b/src/VBox/Runtime/common/string/mempcpy.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memset.asm b/src/VBox/Runtime/common/string/memset.asm
index 96cc48ec..a2d562ba 100644
--- a/src/VBox/Runtime/common/string/memset.asm
+++ b/src/VBox/Runtime/common/string/memset.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memset.cpp b/src/VBox/Runtime/common/string/memset.cpp
index 9bf35893..9935bef5 100644
--- a/src/VBox/Runtime/common/string/memset.cpp
+++ b/src/VBox/Runtime/common/string/memset.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/memset_alias.c b/src/VBox/Runtime/common/string/memset_alias.c
index 49d4abd3..64793471 100644
--- a/src/VBox/Runtime/common/string/memset_alias.c
+++ b/src/VBox/Runtime/common/string/memset_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/simplepattern.cpp b/src/VBox/Runtime/common/string/simplepattern.cpp
index f54d4ce0..6f6bdd2b 100644
--- a/src/VBox/Runtime/common/string/simplepattern.cpp
+++ b/src/VBox/Runtime/common/string/simplepattern.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/straprintf.cpp b/src/VBox/Runtime/common/string/straprintf.cpp
index a0ee0350..a09abd33 100644
--- a/src/VBox/Runtime/common/string/straprintf.cpp
+++ b/src/VBox/Runtime/common/string/straprintf.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strcache.cpp b/src/VBox/Runtime/common/string/strcache.cpp
index 642d5836..e452a4a7 100644
--- a/src/VBox/Runtime/common/string/strcache.cpp
+++ b/src/VBox/Runtime/common/string/strcache.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,12 +31,93 @@
#include <iprt/strcache.h>
#include "internal/iprt.h"
+#include <iprt/alloca.h>
#include <iprt/asm.h>
#include <iprt/assert.h>
+#include <iprt/critsect.h>
#include <iprt/err.h>
-#include <iprt/mempool.h>
-#include <iprt/string.h>
+#include <iprt/list.h>
+#include <iprt/mem.h>
#include <iprt/once.h>
+#include <iprt/param.h>
+#include <iprt/string.h>
+
+#include "internal/strhash.h"
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** Special NIL pointer for the hash table. It differs from NULL in that it is
+ * a valid hash table entry when doing a lookup. */
+#define PRTSTRCACHEENTRY_NIL ((PRTSTRCACHEENTRY)~(uintptr_t)1)
+
+/** Calcuates the increment when handling a collision.
+ * The current formula makes sure it's always odd so we cannot possibly end
+ * up a cyclic loop with an even sized table. It also takes more bits from
+ * the length part. */
+#define RTSTRCACHE_COLLISION_INCR(uHashLen) ( ((uHashLen >> 8) | 1) )
+
+/** The initial hash table size. Must be power of two. */
+#define RTSTRCACHE_INITIAL_HASH_SIZE 512
+/** The hash table growth factor. */
+#define RTSTRCACHE_HASH_GROW_FACTOR 4
+
+/**
+ * The RTSTRCACHEENTRY size threshold at which we stop using our own allocator
+ * and switch to the application heap, expressed as a power of two.
+ *
+ * Using a 1KB as a reasonable limit here.
+ */
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+# define RTSTRCACHE_HEAP_THRESHOLD_BIT 10
+#else
+# define RTSTRCACHE_HEAP_THRESHOLD_BIT 9
+#endif
+/** The RTSTRCACHE_HEAP_THRESHOLD_BIT as a byte limit. */
+#define RTSTRCACHE_HEAP_THRESHOLD RT_BIT_32(RTSTRCACHE_HEAP_THRESHOLD_BIT)
+/** Big (heap) entry size alignment. */
+#define RTSTRCACHE_HEAP_ENTRY_SIZE_ALIGN 16
+
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+/**
+ * The RTSTRCACHEENTRY size threshold at which we start using the merge free
+ * list for allocations, expressed as a power of two.
+ */
+# define RTSTRCACHE_MERGED_THRESHOLD_BIT 6
+
+/** The number of bytes (power of two) that the merged allocation lists should
+ * be grown by. Must be much greater than RTSTRCACHE_MERGED_THRESHOLD. */
+# define RTSTRCACHE_MERGED_GROW_SIZE _32K
+#endif
+
+/** The number of bytes (power of two) that the fixed allocation lists should
+ * be grown by. */
+#define RTSTRCACHE_FIXED_GROW_SIZE _32K
+
+/** The number of fixed sized lists. */
+#define RTSTRCACHE_NUM_OF_FIXED_SIZES 12
+
+
+/** Validates a string cache handle, translating RTSTRCACHE_DEFAULT when found,
+ * and returns rc if not valid. */
+#define RTSTRCACHE_VALID_RETURN_RC(pStrCache, rc) \
+ do { \
+ if ((pStrCache) == RTSTRCACHE_DEFAULT) \
+ { \
+ int rcOnce = RTOnce(&g_rtStrCacheOnce, rtStrCacheInitDefault, NULL); \
+ if (RT_FAILURE(rcOnce)) \
+ return (rc); \
+ (pStrCache) = g_hrtStrCacheDefault; \
+ } \
+ else \
+ { \
+ AssertPtrReturn((pStrCache), (rc)); \
+ AssertReturn((pStrCache)->u32Magic == RTSTRCACHE_MAGIC, (rc)); \
+ } \
+ } while (0)
+
/*******************************************************************************
@@ -44,117 +125,790 @@
*******************************************************************************/
/**
* String cache entry.
- *
- * Each entry is
*/
typedef struct RTSTRCACHEENTRY
{
/** The number of references. */
uint32_t volatile cRefs;
- /** Offset into the chunk (bytes). */
- uint32_t offChunk;
- /** The string length. */
- uint32_t cch;
- /** The primary hash value. */
- uint32_t uHash1;
+ /** The lower 16-bit hash value. */
+ uint16_t uHash;
+ /** The string length (excluding the terminator).
+ * If this is set to RTSTRCACHEENTRY_BIG_LEN, this is a BIG entry
+ * (RTSTRCACHEBIGENTRY). */
+ uint16_t cchString;
/** The string. */
- char szString[16];
+ char szString[8];
} RTSTRCACHEENTRY;
-AssertCompileSize(RTSTRCACHEENTRY, 32);
+AssertCompileSize(RTSTRCACHEENTRY, 16);
/** Pointer to a string cache entry. */
typedef RTSTRCACHEENTRY *PRTSTRCACHEENTRY;
/** Pointer to a const string cache entry. */
typedef RTSTRCACHEENTRY *PCRTSTRCACHEENTRY;
+/** RTSTCACHEENTRY::cchString value for big cache entries. */
+#define RTSTRCACHEENTRY_BIG_LEN UINT16_MAX
+
+/**
+ * Big string cache entry.
+ *
+ * These are allocated individually from the application heap.
+ */
+typedef struct RTSTRCACHEBIGENTRY
+{
+ /** List entry. */
+ RTLISTNODE ListEntry;
+ /** The string length. */
+ uint32_t cchString;
+ /** The full hash value / padding. */
+ uint32_t uHash;
+ /** The core entry. */
+ RTSTRCACHEENTRY Core;
+} RTSTRCACHEBIGENTRY;
+AssertCompileSize(RTSTRCACHEENTRY, 16);
+/** Pointer to a big string cache entry. */
+typedef RTSTRCACHEBIGENTRY *PRTSTRCACHEBIGENTRY;
+/** Pointer to a const big string cache entry. */
+typedef RTSTRCACHEBIGENTRY *PCRTSTRCACHEBIGENTRY;
+
+
/**
- * Allocation chunk.
+ * A free string cache entry.
+ */
+typedef struct RTSTRCACHEFREE
+{
+ /** Zero value indicating that it's a free entry (no refs, no hash). */
+ uint32_t uZero;
+ /** Number of free bytes. Only used for > 32 byte allocations. */
+ uint32_t cbFree;
+ /** Pointer to the next free item. */
+ struct RTSTRCACHEFREE *pNext;
+} RTSTRCACHEFREE;
+AssertCompileSize(RTSTRCACHEENTRY, 16);
+AssertCompileMembersAtSameOffset(RTSTRCACHEENTRY, cRefs, RTSTRCACHEFREE, uZero);
+AssertCompileMembersAtSameOffset(RTSTRCACHEENTRY, szString, RTSTRCACHEFREE, pNext);
+/** Pointer to a free string cache entry. */
+typedef RTSTRCACHEFREE *PRTSTRCACHEFREE;
+
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+
+/**
+ * A free string cache entry with merging.
+ *
+ * This differs from RTSTRCACHEFREE only in having a back pointer for more
+ * efficient list management (doubly vs. singly linked lists).
+ */
+typedef struct RTSTRCACHEFREEMERGE
+{
+ /** Marker that indicates what kind of entry this is, either . */
+ uint32_t uMarker;
+ /** Number of free bytes. Only used for > 32 byte allocations. */
+ uint32_t cbFree;
+ /** Pointer to the main node. NULL for main nodes. */
+ struct RTSTRCACHEFREEMERGE *pMain;
+ /** The free list entry. */
+ RTLISTNODE ListEntry;
+ /** Pads the size up to the minimum allocation unit for the merge list.
+ * This both defines the minimum allocation unit and simplifies pointer
+ * manipulation during merging and splitting. */
+ uint8_t abPadding[ARCH_BITS == 32 ? 44 : 32];
+} RTSTRCACHEFREEMERGE;
+AssertCompileSize(RTSTRCACHEFREEMERGE, RT_BIT_32(RTSTRCACHE_MERGED_THRESHOLD_BIT));
+/** Pointer to a free cache string in the merge list. */
+typedef RTSTRCACHEFREEMERGE *PRTSTRCACHEFREEMERGE;
+
+/** RTSTRCACHEFREEMERGE::uMarker value indicating that it's the real free chunk
+ * header. Must be something that's invalid UTF-8 for both little and big
+ * endian system. */
+# define RTSTRCACHEFREEMERGE_MAIN UINT32_C(0xfffffff1)
+/** RTSTRCACHEFREEMERGE::uMarker value indicating that it's part of a larger
+ * chunk of free memory. Must be something that's invalid UTF-8 for both little
+ * and big endian system. */
+# define RTSTRCACHEFREEMERGE_PART UINT32_C(0xfffffff2)
+
+#endif /* RTSTRCACHE_WITH_MERGED_ALLOCATOR */
+
+/**
+ * Tracking structure chunk of memory used by the 16 byte or 32 byte
+ * allocations.
+ *
+ * This occupies the first entry in the chunk.
*/
typedef struct RTSTRCACHECHUNK
{
- /** Pointer to the main string cache structure. */
- struct RTSTRCACHEINT *pCache;
- /** Padding to align the entries on a 32-byte boundary. */
- uint32_t au32Padding[8 - (ARCH_BITS == 64) - 4];
- /** The index of the first unused entry. */
- uint32_t iUnused;
- /** The number of used entries. */
- uint32_t cUsed;
- /** The number of entries in this chunk. */
- uint32_t cEntries;
- /** The string cache entries, variable size. */
- RTSTRCACHEENTRY aEntries[1];
+ /** The size of the chunk. */
+ size_t cb;
+ /** Pointer to the next chunk. */
+ struct RTSTRCACHECHUNK *pNext;
} RTSTRCACHECHUNK;
+AssertCompile(sizeof(RTSTRCACHECHUNK) <= sizeof(RTSTRCACHEENTRY));
+/** Pointer to the chunk tracking structure. */
+typedef RTSTRCACHECHUNK *PRTSTRCACHECHUNK;
+/**
+ * Cache instance data.
+ */
typedef struct RTSTRCACHEINT
{
/** The string cache magic (RTSTRCACHE_MAGIC). */
- uint32_t u32Magic;
+ uint32_t u32Magic;
+ /** Ref counter for the cache handle. */
+ uint32_t volatile cRefs;
+ /** The number of strings currently entered in the cache. */
+ uint32_t cStrings;
+ /** The size of the hash table. */
+ uint32_t cHashTab;
+ /** Pointer to the hash table. */
+ PRTSTRCACHEENTRY *papHashTab;
+ /** Free list for allocations of the sizes defined by g_acbFixedLists. */
+ PRTSTRCACHEFREE apFreeLists[RTSTRCACHE_NUM_OF_FIXED_SIZES];
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+ /** Free lists based on */
+ RTLISTANCHOR aMergedFreeLists[RTSTRCACHE_HEAP_THRESHOLD_BIT - RTSTRCACHE_MERGED_THRESHOLD_BIT + 1];
+#endif
+ /** List of allocated memory chunks. */
+ PRTSTRCACHECHUNK pChunkList;
+ /** List of big cache entries. */
+ RTLISTANCHOR BigEntryList;
-} RTSTRCACHEINT;
+ /** @name Statistics
+ * @{ */
+ /** The total size of all chunks. */
+ size_t cbChunks;
+ /** The total length of all the strings, terminators included. */
+ size_t cbStrings;
+ /** The total size of all the big entries. */
+ size_t cbBigEntries;
+ /** Hash collisions. */
+ uint32_t cHashCollisions;
+ /** Secondary hash collisions. */
+ uint32_t cHashCollisions2;
+ /** The number of inserts to compare cHashCollisions to. */
+ uint32_t cHashInserts;
+ /** The number of rehashes. */
+ uint32_t cRehashes;
+ /** @} */
+ /** Critical section protecting the cache structures. */
+ RTCRITSECT CritSect;
+} RTSTRCACHEINT;
+/** Pointer to a cache instance. */
+typedef RTSTRCACHEINT *PRTSTRCACHEINT;
/*******************************************************************************
-* Defined Constants And Macros *
+* Global Variables *
*******************************************************************************/
-/** Validates a string cache handle, translating RTSTRCACHE_DEFAULT when found,
- * and returns rc if not valid. */
-#define RTSTRCACHE_VALID_RETURN_RC(pStrCache, rc) \
- do { \
- if ((pStrCache) == RTMEMPOOL_DEFAULT) \
- (pStrCache) = &g_rtMemPoolDefault; \
- else \
- { \
- AssertPtrReturn((pStrCache), (rc)); \
- AssertReturn((pStrCache)->u32Magic == RTSTRCACHE_MAGIC, (rc)); \
- } \
- } while (0)
+/** The entry sizes of the fixed lists (RTSTRCACHEINT::apFreeLists). */
+static const uint32_t g_acbFixedLists[RTSTRCACHE_NUM_OF_FIXED_SIZES] =
+{
+ 16, 32, 48, 64, 96, 128, 192, 256, 320, 384, 448, 512
+};
-/** Validates a memory pool entry and returns rc if not valid. */
-#define RTSTRCACHE_VALID_ENTRY_RETURN_RC(pEntry, rc) \
- do { \
- AssertPtrReturn(pEntry, (rc)); \
- AssertPtrNullReturn((pEntry)->pMemPool, (rc)); \
- Assert((pEntry)->cRefs < UINT32_MAX / 2); \
- AssertReturn((pEntry)->pMemPool->u32Magic == RTMEMPOOL_MAGIC, (rc)); \
- } while (0)
+/** Init once for the default string cache. */
+static RTONCE g_rtStrCacheOnce = RTONCE_INITIALIZER;
+/** The default string cache. */
+static RTSTRCACHE g_hrtStrCacheDefault = NIL_RTSTRCACHE;
-/*******************************************************************************
-* Global Variables *
-*******************************************************************************/
-
+/** @callback_method_impl{FNRTONCE, Initializes g_hrtStrCacheDefault} */
+static DECLCALLBACK(int) rtStrCacheInitDefault(void *pvUser)
+{
+ NOREF(pvUser);
+ return RTStrCacheCreate(&g_hrtStrCacheDefault, "Default");
+}
RTDECL(int) RTStrCacheCreate(PRTSTRCACHE phStrCache, const char *pszName)
{
- AssertCompile(sizeof(RTSTRCACHE) == sizeof(RTMEMPOOL));
- AssertCompile(NIL_RTSTRCACHE == (RTSTRCACHE)NIL_RTMEMPOOL);
- AssertCompile(RTSTRCACHE_DEFAULT == (RTSTRCACHE)RTMEMPOOL_DEFAULT);
- return RTMemPoolCreate((PRTMEMPOOL)phStrCache, pszName);
+ int rc = VERR_NO_MEMORY;
+ PRTSTRCACHEINT pThis = (PRTSTRCACHEINT)RTMemAllocZ(sizeof(*pThis));
+ if (pThis)
+ {
+ pThis->cHashTab = RTSTRCACHE_INITIAL_HASH_SIZE;
+ pThis->papHashTab = (PRTSTRCACHEENTRY*)RTMemAllocZ(sizeof(pThis->papHashTab[0]) * pThis->cHashTab);
+ if (pThis->papHashTab)
+ {
+ rc = RTCritSectInit(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ RTListInit(&pThis->BigEntryList);
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+ for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aMergedFreeLists); i++)
+ RTListInit(&pThis->aMergedFreeLists[i]);
+#endif
+ pThis->cRefs = 1;
+ pThis->u32Magic = RTSTRCACHE_MAGIC;
+
+ *phStrCache = pThis;
+ return VINF_SUCCESS;
+ }
+ RTMemFree(pThis->papHashTab);
+ }
+ RTMemFree(pThis);
+ }
+ return rc;
}
RT_EXPORT_SYMBOL(RTStrCacheCreate);
RTDECL(int) RTStrCacheDestroy(RTSTRCACHE hStrCache)
{
- if ( hStrCache == NIL_RTSTRCACHE
- || hStrCache == RTSTRCACHE_DEFAULT)
+ if ( hStrCache == NIL_RTSTRCACHE
+ || hStrCache == RTSTRCACHE_DEFAULT)
return VINF_SUCCESS;
- return RTMemPoolDestroy((RTMEMPOOL)hStrCache);
+
+ PRTSTRCACHEINT pThis = hStrCache;
+ RTSTRCACHE_VALID_RETURN_RC(pThis, VERR_INVALID_HANDLE);
+
+ /*
+ * Invalidate it. Enter the crit sect just to be on the safe side.
+ */
+ AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSTRCACHE_MAGIC_DEAD, RTSTRCACHE_MAGIC), VERR_INVALID_HANDLE);
+ RTCritSectEnter(&pThis->CritSect);
+ Assert(pThis->cRefs == 1);
+
+ PRTSTRCACHECHUNK pChunk;
+ while ((pChunk = pThis->pChunkList) != NULL)
+ {
+ pThis->pChunkList = pChunk->pNext;
+ RTMemPageFree(pChunk, pChunk->cb);
+ }
+
+ RTMemFree(pThis->papHashTab);
+ pThis->papHashTab = NULL;
+ pThis->cHashTab = 0;
+
+ PRTSTRCACHEBIGENTRY pCur, pNext;
+ RTListForEachSafe(&pThis->BigEntryList, pCur, pNext, RTSTRCACHEBIGENTRY, ListEntry)
+ {
+ RTMemFree(pCur);
+ }
+
+ RTCritSectLeave(&pThis->CritSect);
+ RTCritSectDelete(&pThis->CritSect);
+
+ RTMemFree(pThis);
+ return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTStrCacheDestroy);
+/**
+ * Selects the fixed free list index for a given minimum entry size.
+ *
+ * @returns Free list index.
+ * @param cbMin Minimum entry size.
+ */
+DECLINLINE(uint32_t) rtStrCacheSelectFixedList(uint32_t cbMin)
+{
+ Assert(cbMin <= g_acbFixedLists[RT_ELEMENTS(g_acbFixedLists) - 1]);
+ unsigned i = 0;
+ while (cbMin > g_acbFixedLists[i])
+ i++;
+ return i;
+}
+
+
+#ifdef RT_STRICT
+# define RTSTRCACHE_CHECK(a_pThis) do { rtStrCacheCheck(pThis); } while (0)
+/**
+ * Internal cache check.
+ */
+static void rtStrCacheCheck(PRTSTRCACHEINT pThis)
+{
+# ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+ for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aMergedFreeLists); i++)
+ {
+ PRTSTRCACHEFREEMERGE pFree;
+ RTListForEach(&pThis->aMergedFreeLists[i], pFree, RTSTRCACHEFREEMERGE, ListEntry)
+ {
+ Assert(pFree->uMarker == RTSTRCACHEFREEMERGE_MAIN);
+ Assert(pFree->cbFree > 0);
+ Assert(RT_ALIGN_32(pFree->cbFree, sizeof(*pFree)) == pFree->cbFree);
+ }
+ }
+# endif
+}
+#else
+# define RTSTRCACHE_CHECK(a_pThis) do { } while (0)
+#endif
+
+
+/**
+ * Finds the first empty hash table entry given a hash+length value.
+ *
+ * ASSUMES that the hash table isn't full.
+ *
+ * @returns Hash table index.
+ * @param pThis The string cache instance.
+ * @param uHashLen The hash + length (not RTSTRCACHEENTRY_BIG_LEN).
+ */
+static uint32_t rtStrCacheFindEmptyHashTabEntry(PRTSTRCACHEINT pThis, uint32_t uHashLen)
+{
+ uint32_t iHash = uHashLen % pThis->cHashTab;
+ for (;;)
+ {
+ PRTSTRCACHEENTRY pEntry = pThis->papHashTab[iHash];
+ if (pEntry == NULL || pEntry == PRTSTRCACHEENTRY_NIL)
+ return iHash;
+
+ /* Advance. */
+ iHash += RTSTRCACHE_COLLISION_INCR(uHashLen);
+ iHash %= pThis->cHashTab;
+ }
+}
+
+/**
+ * Grows the hash table.
+ *
+ * @returns vINF_SUCCESS or VERR_NO_MEMORY.
+ * @param pThis The string cache instance.
+ */
+static int rtStrCacheGrowHashTab(PRTSTRCACHEINT pThis)
+{
+ /*
+ * Allocate a new hash table two times the size of the old one.
+ */
+ uint32_t cNew = pThis->cHashTab * RTSTRCACHE_HASH_GROW_FACTOR;
+ PRTSTRCACHEENTRY *papNew = (PRTSTRCACHEENTRY *)RTMemAllocZ(sizeof(papNew[0]) * cNew);
+ if (papNew == NULL)
+ return VERR_NO_MEMORY;
+
+ /*
+ * Install the new table and move the items from the old table and into the new one.
+ */
+ PRTSTRCACHEENTRY *papOld = pThis->papHashTab;
+ uint32_t iOld = pThis->cHashTab;
+
+ pThis->papHashTab = papNew;
+ pThis->cHashTab = cNew;
+ pThis->cRehashes++;
+
+ while (iOld-- > 0)
+ {
+ PRTSTRCACHEENTRY pEntry = papOld[iOld];
+ if (pEntry != NULL && pEntry != PRTSTRCACHEENTRY_NIL)
+ {
+ uint32_t cchString = pEntry->cchString;
+ if (cchString == RTSTRCACHEENTRY_BIG_LEN)
+ cchString = RT_FROM_MEMBER(pEntry, RTSTRCACHEBIGENTRY, Core)->cchString;
+
+ uint32_t iHash = rtStrCacheFindEmptyHashTabEntry(pThis, RT_MAKE_U32(pEntry->uHash, cchString));
+ pThis->papHashTab[iHash] = pEntry;
+ }
+ }
+
+ /*
+ * Free the old hash table.
+ */
+ RTMemFree(papOld);
+ return VINF_SUCCESS;
+}
+
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+
+/**
+ * Link/Relink into the free right list.
+ *
+ * @param pThis The string cache instance.
+ * @param pFree The free string entry.
+ */
+static void rtStrCacheRelinkMerged(PRTSTRCACHEINT pThis, PRTSTRCACHEFREEMERGE pFree)
+{
+ Assert(pFree->uMarker == RTSTRCACHEFREEMERGE_MAIN);
+ Assert(pFree->cbFree > 0);
+ Assert(RT_ALIGN_32(pFree->cbFree, sizeof(*pFree)) == pFree->cbFree);
+
+ if (!RTListIsEmpty(&pFree->ListEntry))
+ RTListNodeRemove(&pFree->ListEntry);
+
+ uint32_t iList = (ASMBitLastSetU32(pFree->cbFree) - 1) - RTSTRCACHE_MERGED_THRESHOLD_BIT;
+ if (iList >= RT_ELEMENTS(pThis->aMergedFreeLists))
+ iList = RT_ELEMENTS(pThis->aMergedFreeLists) - 1;
+
+ RTListPrepend(&pThis->aMergedFreeLists[iList], &pFree->ListEntry);
+}
+
+
+/**
+ * Allocate a cache entry from the merged free lists.
+ *
+ * @returns Pointer to the cache entry on success, NULL on allocation error.
+ * @param pThis The string cache instance.
+ * @param uHash The full hash of the string.
+ * @param pchString The string.
+ * @param cchString The string length.
+ * @param cbEntry The required entry size.
+ */
+static PRTSTRCACHEENTRY rtStrCacheAllocMergedEntry(PRTSTRCACHEINT pThis, uint32_t uHash,
+ const char *pchString, uint32_t cchString, uint32_t cbEntry)
+{
+ cbEntry = RT_ALIGN_32(cbEntry, sizeof(RTSTRCACHEFREEMERGE));
+ Assert(cbEntry > cchString);
+
+ /*
+ * Search the list heads first.
+ */
+ PRTSTRCACHEFREEMERGE pFree = NULL;
+
+ uint32_t iList = ASMBitLastSetU32(cbEntry) - 1;
+ if (!RT_IS_POWER_OF_TWO(cbEntry))
+ iList++;
+ iList -= RTSTRCACHE_MERGED_THRESHOLD_BIT;
+
+ while (iList < RT_ELEMENTS(pThis->aMergedFreeLists))
+ {
+ pFree = RTListGetFirst(&pThis->aMergedFreeLists[iList], RTSTRCACHEFREEMERGE, ListEntry);
+ if (pFree)
+ {
+ /*
+ * Found something. Should we we split it? We split from the end
+ * to avoid having to update all the sub entries.
+ */
+ Assert(pFree->uMarker == RTSTRCACHEFREEMERGE_MAIN);
+ Assert(pFree->cbFree >= cbEntry);
+ Assert(RT_ALIGN_32(pFree->cbFree, sizeof(*pFree)) == pFree->cbFree);
+
+ if (pFree->cbFree == cbEntry)
+ RTListNodeRemove(&pFree->ListEntry);
+ else
+ {
+ uint32_t cRemainder = (pFree->cbFree - cbEntry) / sizeof(*pFree);
+ PRTSTRCACHEFREEMERGE pRemainder = pFree;
+ pFree += cRemainder;
+
+ Assert((pRemainder->cbFree - cbEntry) == cRemainder * sizeof(*pFree));
+ pRemainder->cbFree = cRemainder * sizeof(*pFree);
+
+ rtStrCacheRelinkMerged(pThis, pRemainder);
+ }
+ break;
+ }
+ iList++;
+ }
+ if (!pFree)
+ {
+ /*
+ * Allocate a new block. (We could search the list below in some
+ * cases, but it's too much effort to write and execute).
+ */
+ size_t const cbChunk = RTSTRCACHE_MERGED_GROW_SIZE; AssertReturn(cbChunk > cbEntry * 2, NULL);
+ PRTSTRCACHECHUNK pChunk = (PRTSTRCACHECHUNK)RTMemPageAlloc(cbChunk);
+ if (!pChunk)
+ return NULL;
+ pChunk->cb = cbChunk;
+ pChunk->pNext = pThis->pChunkList;
+ pThis->pChunkList = pChunk;
+ pThis->cbChunks += cbChunk;
+ AssertCompile(sizeof(*pChunk) <= sizeof(*pFree));
+
+ /*
+ * Get one node for the allocation at hand.
+ */
+ pFree = (PRTSTRCACHEFREEMERGE)((uintptr_t)pChunk + sizeof(*pFree));
+
+ /*
+ * Create a free block out of the remainder (always a reminder).
+ */
+ PRTSTRCACHEFREEMERGE pNewFree = (PRTSTRCACHEFREEMERGE)((uintptr_t)pFree + cbEntry);
+ pNewFree->uMarker = RTSTRCACHEFREEMERGE_MAIN;
+ pNewFree->cbFree = cbChunk - sizeof(*pNewFree) - cbEntry; Assert(pNewFree->cbFree < cbChunk && pNewFree->cbFree > 0);
+ pNewFree->pMain = NULL;
+ RTListInit(&pNewFree->ListEntry);
+
+ uint32_t iInternalBlock = pNewFree->cbFree / sizeof(*pNewFree);
+ while (iInternalBlock-- > 1)
+ {
+ pNewFree[iInternalBlock].uMarker = RTSTRCACHEFREEMERGE_PART;
+ pNewFree[iInternalBlock].cbFree = 0;
+ pNewFree[iInternalBlock].pMain = pNewFree;
+ }
+
+ rtStrCacheRelinkMerged(pThis, pNewFree);
+ }
+
+ /*
+ * Initialize the entry. We zero all bytes we don't use so they cannot
+ * accidentally be mistaken for a free entry.
+ */
+ ASMCompilerBarrier();
+ PRTSTRCACHEENTRY pEntry = (PRTSTRCACHEENTRY)pFree;
+ pEntry->cRefs = 1;
+ pEntry->uHash = (uint16_t)uHash;
+ pEntry->cchString = (uint16_t)cchString;
+ memcpy(pEntry->szString, pchString, cchString);
+ RT_BZERO(&pEntry->szString[cchString], cbEntry - RT_UOFFSETOF(RTSTRCACHEENTRY, szString) - cchString);
+
+ RTSTRCACHE_CHECK(pThis);
+
+ return pEntry;
+}
+
+#endif /* RTSTRCACHE_WITH_MERGED_ALLOCATOR */
+
+/**
+ * Allocate a cache entry from the heap.
+ *
+ * @returns Pointer to the cache entry on success, NULL on allocation error.
+ * @param pThis The string cache instance.
+ * @param uHash The full hash of the string.
+ * @param pchString The string.
+ * @param cchString The string length.
+ */
+static PRTSTRCACHEENTRY rtStrCacheAllocHeapEntry(PRTSTRCACHEINT pThis, uint32_t uHash,
+ const char *pchString, uint32_t cchString)
+{
+ /*
+ * Allocate a heap block for storing the string. We do some size aligning
+ * here to encourage the heap to give us optimal alignment.
+ */
+ size_t cbEntry = RT_UOFFSETOF(RTSTRCACHEBIGENTRY, Core.szString[cchString + 1]);
+ PRTSTRCACHEBIGENTRY pBigEntry = (PRTSTRCACHEBIGENTRY)RTMemAlloc(RT_ALIGN_Z(cbEntry, RTSTRCACHE_HEAP_ENTRY_SIZE_ALIGN));
+ if (!pBigEntry)
+ return NULL;
+
+ /*
+ * Initialize the block.
+ */
+ RTListAppend(&pThis->BigEntryList, &pBigEntry->ListEntry);
+ pThis->cbBigEntries += cbEntry;
+ pBigEntry->cchString = cchString;
+ pBigEntry->uHash = uHash;
+ pBigEntry->Core.cRefs = 1;
+ pBigEntry->Core.uHash = (uint16_t)uHash;
+ pBigEntry->Core.cchString = RTSTRCACHEENTRY_BIG_LEN;
+ memcpy(pBigEntry->Core.szString, pchString, cchString);
+ pBigEntry->Core.szString[cchString] = '\0';
+
+ return &pBigEntry->Core;
+}
+
+
+/**
+ * Allocate a cache entry from a fixed size free list.
+ *
+ * @returns Pointer to the cache entry on success, NULL on allocation error.
+ * @param pThis The string cache instance.
+ * @param uHash The full hash of the string.
+ * @param pchString The string.
+ * @param cchString The string length.
+ * @param iFreeList Which free list.
+ */
+static PRTSTRCACHEENTRY rtStrCacheAllocFixedEntry(PRTSTRCACHEINT pThis, uint32_t uHash,
+ const char *pchString, uint32_t cchString, uint32_t iFreeList)
+{
+ /*
+ * Get an entry from the free list. If empty, allocate another chunk of
+ * memory and split it up into free entries of the desired size.
+ */
+ PRTSTRCACHEFREE pFree = pThis->apFreeLists[iFreeList];
+ if (!pFree)
+ {
+ PRTSTRCACHECHUNK pChunk = (PRTSTRCACHECHUNK)RTMemPageAlloc(RTSTRCACHE_FIXED_GROW_SIZE);
+ if (!pChunk)
+ return NULL;
+ pChunk->cb = RTSTRCACHE_FIXED_GROW_SIZE;
+ pChunk->pNext = pThis->pChunkList;
+ pThis->pChunkList = pChunk;
+ pThis->cbChunks += RTSTRCACHE_FIXED_GROW_SIZE;
+
+ PRTSTRCACHEFREE pPrev = NULL;
+ uint32_t const cbEntry = g_acbFixedLists[iFreeList];
+ uint32_t cLeft = RTSTRCACHE_FIXED_GROW_SIZE / cbEntry - 1;
+ pFree = (PRTSTRCACHEFREE)((uintptr_t)pChunk + cbEntry);
+
+ Assert(sizeof(*pChunk) <= cbEntry);
+ Assert(sizeof(*pFree) <= cbEntry);
+ Assert(cbEntry < RTSTRCACHE_FIXED_GROW_SIZE / 16);
+
+ while (cLeft-- > 0)
+ {
+ pFree->uZero = 0;
+ pFree->cbFree = cbEntry;
+ pFree->pNext = pPrev;
+ pPrev = pFree;
+ pFree = (PRTSTRCACHEFREE)((uintptr_t)pFree + cbEntry);
+ }
+
+ Assert(pPrev);
+ pThis->apFreeLists[iFreeList] = pFree = pPrev;
+ }
+
+ /*
+ * Unlink it.
+ */
+ pThis->apFreeLists[iFreeList] = pFree->pNext;
+ ASMCompilerBarrier();
+
+ /*
+ * Initialize the entry.
+ */
+ PRTSTRCACHEENTRY pEntry = (PRTSTRCACHEENTRY)pFree;
+ pEntry->cRefs = 1;
+ pEntry->uHash = (uint16_t)uHash;
+ pEntry->cchString = (uint16_t)cchString;
+ memcpy(pEntry->szString, pchString, cchString);
+ pEntry->szString[cchString] = '\0';
+
+ return pEntry;
+}
+
+
+/**
+ * Looks up a string in the hash table.
+ *
+ * @returns Pointer to the string cache entry, NULL + piFreeHashTabEntry if not
+ * found.
+ * @param pThis The string cache instance.
+ * @param uHashLen The hash + length (not RTSTRCACHEENTRY_BIG_LEN).
+ * @param cchString The real length.
+ * @param pchString The string.
+ * @param piFreeHashTabEntry Where to store the index insertion index if NULL
+ * is returned (same as what
+ * rtStrCacheFindEmptyHashTabEntry would return).
+ * @param pcCollisions Where to return a collision counter.
+ */
+static PRTSTRCACHEENTRY rtStrCacheLookUp(PRTSTRCACHEINT pThis, uint32_t uHashLen, uint32_t cchString, const char *pchString,
+ uint32_t *piFreeHashTabEntry, uint32_t *pcCollisions)
+{
+ *piFreeHashTabEntry = UINT32_MAX;
+ *pcCollisions = 0;
+
+ uint16_t cchStringFirst = RT_UOFFSETOF(RTSTRCACHEENTRY, szString[cchString + 1]) < RTSTRCACHE_HEAP_THRESHOLD
+ ? (uint16_t)cchString : RTSTRCACHEENTRY_BIG_LEN;
+ uint32_t iHash = uHashLen % pThis->cHashTab;
+ for (;;)
+ {
+ PRTSTRCACHEENTRY pEntry = pThis->papHashTab[iHash];
+
+ /* Give up if NULL, but record the index for insertion. */
+ if (pEntry == NULL)
+ {
+ if (*piFreeHashTabEntry == UINT32_MAX)
+ *piFreeHashTabEntry = iHash;
+ return NULL;
+ }
+
+ if (pEntry != PRTSTRCACHEENTRY_NIL)
+ {
+ /* Compare. */
+ if ( pEntry->uHash == (uint16_t)uHashLen
+ && pEntry->cchString == cchStringFirst)
+ {
+ if (pEntry->cchString != RTSTRCACHEENTRY_BIG_LEN)
+ {
+ if ( !memcmp(pEntry->szString, pchString, cchString)
+ && pEntry->szString[cchString] == '\0')
+ return pEntry;
+ }
+ else
+ {
+ PRTSTRCACHEBIGENTRY pBigEntry = RT_FROM_MEMBER(pEntry, RTSTRCACHEBIGENTRY, Core);
+ if ( pBigEntry->cchString == cchString
+ && !memcmp(pBigEntry->Core.szString, pchString, cchString))
+ return &pBigEntry->Core;
+ }
+ }
+
+ if (*piFreeHashTabEntry == UINT32_MAX)
+ *pcCollisions += 1;
+ }
+ /* Record the first NIL index for insertion in case we don't get a hit. */
+ else if (*piFreeHashTabEntry == UINT32_MAX)
+ *piFreeHashTabEntry = iHash;
+
+ /* Advance. */
+ iHash += RTSTRCACHE_COLLISION_INCR(uHashLen);
+ iHash %= pThis->cHashTab;
+ }
+}
+
+
RTDECL(const char *) RTStrCacheEnterN(RTSTRCACHE hStrCache, const char *pchString, size_t cchString)
{
- AssertPtr(pchString);
+ PRTSTRCACHEINT pThis = hStrCache;
+ RTSTRCACHE_VALID_RETURN_RC(pThis, NULL);
+
+
+ /*
+ * Calculate the hash and figure the exact string length, then look for an existing entry.
+ */
+ uint32_t const uHash = sdbmN(pchString, cchString, &cchString);
+ uint32_t const uHashLen = RT_MAKE_U32(uHash, cchString);
AssertReturn(cchString < _1G, NULL);
- Assert(!RTStrEnd(pchString, cchString));
+ uint32_t const cchString32 = (uint32_t)cchString;
+
+ RTCritSectEnter(&pThis->CritSect);
+ RTSTRCACHE_CHECK(pThis);
- return (const char *)RTMemPoolDupEx((RTMEMPOOL)hStrCache, pchString, cchString, 1);
+ uint32_t cCollisions;
+ uint32_t iFreeHashTabEntry;
+ PRTSTRCACHEENTRY pEntry = rtStrCacheLookUp(pThis, uHashLen, cchString32, pchString, &iFreeHashTabEntry, &cCollisions);
+ if (pEntry)
+ {
+ uint32_t cRefs = ASMAtomicIncU32(&pEntry->cRefs);
+ Assert(cRefs < UINT32_MAX / 2);
+ }
+ else
+ {
+ /*
+ * Allocate a new entry.
+ */
+ uint32_t cbEntry = cchString32 + 1U + RT_UOFFSETOF(RTSTRCACHEENTRY, szString);
+ if (cbEntry >= RTSTRCACHE_HEAP_THRESHOLD)
+ pEntry = rtStrCacheAllocHeapEntry(pThis, uHash, pchString, cchString32);
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+ else if (cbEntry >= RTSTRCACHE_MERGED_THRESHOLD_BIT)
+ pEntry = rtStrCacheAllocMergedEntry(pThis, uHash, pchString, cchString32, cbEntry);
+#endif
+ else
+ pEntry = rtStrCacheAllocFixedEntry(pThis, uHash, pchString, cchString32,
+ rtStrCacheSelectFixedList(cbEntry));
+ if (!pEntry)
+ {
+ RTSTRCACHE_CHECK(pThis);
+ RTCritSectLeave(&pThis->CritSect);
+ return NULL;
+ }
+
+ /*
+ * Insert it into the hash table.
+ */
+ if (pThis->cHashTab - pThis->cStrings < pThis->cHashTab / 2)
+ {
+ int rc = rtStrCacheGrowHashTab(pThis);
+ if (RT_SUCCESS(rc))
+ iFreeHashTabEntry = rtStrCacheFindEmptyHashTabEntry(pThis, uHashLen);
+ else if (pThis->cHashTab - pThis->cStrings <= pThis->cHashTab / 8) /* 12.5% full => error */
+ {
+ pThis->papHashTab[iFreeHashTabEntry] = pEntry;
+ pThis->cStrings++;
+ pThis->cHashInserts++;
+ pThis->cHashCollisions += cCollisions > 0;
+ pThis->cHashCollisions2 += cCollisions > 1;
+ pThis->cbStrings += cchString32 + 1;
+ RTStrCacheRelease(hStrCache, pEntry->szString);
+
+ RTSTRCACHE_CHECK(pThis);
+ RTCritSectLeave(&pThis->CritSect);
+ return NULL;
+ }
+ }
+
+ pThis->papHashTab[iFreeHashTabEntry] = pEntry;
+ pThis->cStrings++;
+ pThis->cHashInserts++;
+ pThis->cHashCollisions += cCollisions > 0;
+ pThis->cHashCollisions2 += cCollisions > 1;
+ pThis->cbStrings += cchString32 + 1;
+ Assert(pThis->cStrings < pThis->cHashTab && pThis->cStrings > 0);
+ }
+
+ RTSTRCACHE_CHECK(pThis);
+ RTCritSectLeave(&pThis->CritSect);
+ return pEntry->szString;
}
RT_EXPORT_SYMBOL(RTStrCacheEnterN);
@@ -166,19 +920,249 @@ RTDECL(const char *) RTStrCacheEnter(RTSTRCACHE hStrCache, const char *psz)
RT_EXPORT_SYMBOL(RTStrCacheEnter);
+static const char *rtStrCacheEnterLowerWorker(PRTSTRCACHEINT pThis, const char *pchString, size_t cchString)
+{
+ /*
+ * Try use a dynamic heap buffer first.
+ */
+ if (cchString < 512)
+ {
+ char *pszStackBuf = (char *)alloca(cchString + 1);
+ if (pszStackBuf)
+ {
+ memcpy(pszStackBuf, pchString, cchString);
+ pszStackBuf[cchString] = '\0';
+ RTStrToLower(pszStackBuf);
+ return RTStrCacheEnterN(pThis, pszStackBuf, cchString);
+ }
+ }
+
+ /*
+ * Fall back on heap.
+ */
+ char *pszHeapBuf = (char *)RTMemTmpAlloc(cchString + 1);
+ if (!pszHeapBuf)
+ return NULL;
+ memcpy(pszHeapBuf, pchString, cchString);
+ pszHeapBuf[cchString] = '\0';
+ RTStrToLower(pszHeapBuf);
+ const char *pszRet = RTStrCacheEnterN(pThis, pszHeapBuf, cchString);
+ RTMemTmpFree(pszHeapBuf);
+ return pszRet;
+}
+
+RTDECL(const char *) RTStrCacheEnterLowerN(RTSTRCACHE hStrCache, const char *pchString, size_t cchString)
+{
+ PRTSTRCACHEINT pThis = hStrCache;
+ RTSTRCACHE_VALID_RETURN_RC(pThis, NULL);
+ return rtStrCacheEnterLowerWorker(pThis, pchString, RTStrNLen(pchString, cchString));
+}
+RT_EXPORT_SYMBOL(RTStrCacheEnterLowerN);
+
+
+RTDECL(const char *) RTStrCacheEnterLower(RTSTRCACHE hStrCache, const char *psz)
+{
+ PRTSTRCACHEINT pThis = hStrCache;
+ RTSTRCACHE_VALID_RETURN_RC(pThis, NULL);
+ return rtStrCacheEnterLowerWorker(pThis, psz, strlen(psz));
+}
+RT_EXPORT_SYMBOL(RTStrCacheEnterLower);
+
+
RTDECL(uint32_t) RTStrCacheRetain(const char *psz)
{
AssertPtr(psz);
- return RTMemPoolRetain((void *)psz);
+
+ PRTSTRCACHEENTRY pStr = RT_FROM_MEMBER(psz, RTSTRCACHEENTRY, szString);
+ Assert(!((uintptr_t)pStr & 15) || pStr->cchString == RTSTRCACHEENTRY_BIG_LEN);
+
+ uint32_t cRefs = ASMAtomicIncU32(&pStr->cRefs);
+ Assert(cRefs > 1);
+ Assert(cRefs < UINT32_MAX / 2);
+
+ return cRefs;
}
RT_EXPORT_SYMBOL(RTStrCacheRetain);
+static uint32_t rtStrCacheFreeEntry(PRTSTRCACHEINT pThis, PRTSTRCACHEENTRY pStr)
+{
+ RTCritSectEnter(&pThis->CritSect);
+ RTSTRCACHE_CHECK(pThis);
+
+ /* Remove it from the hash table. */
+ uint32_t cchString = pStr->cchString == RTSTRCACHEENTRY_BIG_LEN
+ ? RT_FROM_MEMBER(pStr, RTSTRCACHEBIGENTRY, Core)->cchString
+ : pStr->cchString;
+ uint32_t uHashLen = RT_MAKE_U32(pStr->uHash, cchString);
+ uint32_t iHash = uHashLen % pThis->cHashTab;
+ if (pThis->papHashTab[iHash] == pStr)
+ pThis->papHashTab[iHash] = PRTSTRCACHEENTRY_NIL;
+ else
+ {
+ do
+ {
+ AssertBreak(pThis->papHashTab[iHash] != NULL);
+ iHash += RTSTRCACHE_COLLISION_INCR(uHashLen);
+ iHash %= pThis->cHashTab;
+ } while (pThis->papHashTab[iHash] != pStr);
+ if (RT_LIKELY(pThis->papHashTab[iHash] == pStr))
+ pThis->papHashTab[iHash] = PRTSTRCACHEENTRY_NIL;
+ else
+ {
+ AssertFailed();
+ iHash = pThis->cHashTab;
+ while (iHash-- > 0)
+ if (pThis->papHashTab[iHash] == pStr)
+ break;
+ AssertMsgFailed(("iHash=%u cHashTab=%u\n", iHash, pThis->cHashTab));
+ }
+ }
+
+ pThis->cStrings--;
+ pThis->cbStrings -= cchString;
+ Assert(pThis->cStrings < pThis->cHashTab);
+
+ /* Free it. */
+ if (pStr->cchString != RTSTRCACHEENTRY_BIG_LEN)
+ {
+ uint32_t const cbMin = pStr->cchString + 1U + RT_UOFFSETOF(RTSTRCACHEENTRY, szString);
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+ if (cbMin <= RTSTRCACHE_MAX_FIXED)
+#endif
+ {
+ /*
+ * No merging, just add it to the list.
+ */
+ uint32_t const iFreeList = rtStrCacheSelectFixedList(cbMin);
+ ASMCompilerBarrier();
+ PRTSTRCACHEFREE pFreeStr = (PRTSTRCACHEFREE)pStr;
+ pFreeStr->cbFree = cbMin;
+ pFreeStr->uZero = 0;
+ pFreeStr->pNext = pThis->apFreeLists[iFreeList];
+ pThis->apFreeLists[iFreeList] = pFreeStr;
+ }
+#ifdef RTSTRCACHE_WITH_MERGED_ALLOCATOR
+ else
+ {
+ /*
+ * Complicated mode, we merge with adjecent nodes.
+ */
+ ASMCompilerBarrier();
+ PRTSTRCACHEFREEMERGE pFreeStr = (PRTSTRCACHEFREEMERGE)pStr;
+ pFreeStr->cbFree = RT_ALIGN_32(cbMin, sizeof(*pFreeStr));
+ pFreeStr->uMarker = RTSTRCACHEFREEMERGE_MAIN;
+ pFreeStr->pMain = NULL;
+ RTListInit(&pFreeStr->ListEntry);
+
+ /*
+ * Merge with previous?
+ * (Reading one block back is safe because there is always the
+ * RTSTRCACHECHUNK structure at the head of each memory chunk.)
+ */
+ uint32_t cInternalBlocks = pFreeStr->cbFree / sizeof(*pFreeStr);
+ PRTSTRCACHEFREEMERGE pMain = pFreeStr - 1;
+ if ( pMain->uMarker == RTSTRCACHEFREEMERGE_MAIN
+ || pMain->uMarker == RTSTRCACHEFREEMERGE_PART)
+ {
+ while (pMain->uMarker != RTSTRCACHEFREEMERGE_MAIN)
+ pMain--;
+ pMain->cbFree += pFreeStr->cbFree;
+ }
+ else
+ {
+ pMain = pFreeStr;
+ pFreeStr++;
+ cInternalBlocks--;
+ }
+
+ /*
+ * Mark internal blocks in the string we're freeing.
+ */
+ while (cInternalBlocks-- > 0)
+ {
+ pFreeStr->uMarker = RTSTRCACHEFREEMERGE_PART;
+ pFreeStr->cbFree = 0;
+ pFreeStr->pMain = pMain;
+ RTListInit(&pFreeStr->ListEntry);
+ pFreeStr++;
+ }
+
+ /*
+ * Merge with next? Limitation: We won't try cross page boundraries.
+ * (pFreeStr points to the next first free enter after the string now.)
+ */
+ if ( PAGE_ADDRESS(pFreeStr) == PAGE_ADDRESS(&pFreeStr[-1])
+ && pFreeStr->uMarker == RTSTRCACHEFREEMERGE_MAIN)
+ {
+ pMain->cbFree += pFreeStr->cbFree;
+ cInternalBlocks = pFreeStr->cbFree / sizeof(*pFreeStr);
+ Assert(cInternalBlocks > 0);
+
+ /* Update the main block we merge with. */
+ pFreeStr->cbFree = 0;
+ pFreeStr->uMarker = RTSTRCACHEFREEMERGE_PART;
+ RTListNodeRemove(&pFreeStr->ListEntry);
+ RTListInit(&pFreeStr->ListEntry);
+
+ /* Change the internal blocks we merged in. */
+ cInternalBlocks--;
+ while (cInternalBlocks-- > 0)
+ {
+ pFreeStr++;
+ pFreeStr->pMain = pMain;
+ Assert(pFreeStr->uMarker == RTSTRCACHEFREEMERGE_PART);
+ Assert(!pFreeStr->cbFree);
+ }
+ }
+
+ /*
+ * Add/relink into the appropriate free list.
+ */
+ rtStrCacheRelinkMerged(pThis, pMain);
+ }
+#endif /* RTSTRCACHE_WITH_MERGED_ALLOCATOR */
+ RTSTRCACHE_CHECK(pThis);
+ RTCritSectLeave(&pThis->CritSect);
+ }
+ else
+ {
+ /* Big string. */
+ PRTSTRCACHEBIGENTRY pBigStr = RT_FROM_MEMBER(pStr, RTSTRCACHEBIGENTRY, Core);
+ RTListNodeRemove(&pBigStr->ListEntry);
+ pThis->cbBigEntries -= RT_ALIGN_32(RT_UOFFSETOF(RTSTRCACHEBIGENTRY, Core.szString[cchString + 1]),
+ RTSTRCACHE_HEAP_ENTRY_SIZE_ALIGN);
+
+ RTSTRCACHE_CHECK(pThis);
+ RTCritSectLeave(&pThis->CritSect);
+
+ RTMemFree(pBigStr);
+ }
+
+ return 0;
+}
+
RTDECL(uint32_t) RTStrCacheRelease(RTSTRCACHE hStrCache, const char *psz)
{
if (!psz)
return 0;
- return RTMemPoolRelease((RTMEMPOOL)hStrCache, (void *)psz);
+
+ PRTSTRCACHEINT pThis = hStrCache;
+ RTSTRCACHE_VALID_RETURN_RC(pThis, UINT32_MAX);
+
+ AssertPtr(psz);
+ PRTSTRCACHEENTRY pStr = RT_FROM_MEMBER(psz, RTSTRCACHEENTRY, szString);
+ Assert(!((uintptr_t)pStr & 15) || pStr->cchString == RTSTRCACHEENTRY_BIG_LEN);
+
+ /*
+ * Drop a reference and maybe free the entry.
+ */
+ uint32_t cRefs = ASMAtomicDecU32(&pStr->cRefs);
+ Assert(cRefs < UINT32_MAX / 2);
+ if (!cRefs)
+ return rtStrCacheFreeEntry(pThis, pStr);
+
+ return cRefs;
}
RT_EXPORT_SYMBOL(RTStrCacheRelease);
@@ -187,7 +1171,54 @@ RTDECL(size_t) RTStrCacheLength(const char *psz)
{
if (!psz)
return 0;
- return strlen(psz);
+
+ AssertPtr(psz);
+ PRTSTRCACHEENTRY pStr = RT_FROM_MEMBER(psz, RTSTRCACHEENTRY, szString);
+ if (pStr->cchString == RTSTRCACHEENTRY_BIG_LEN)
+ {
+ PRTSTRCACHEBIGENTRY pBigStr = RT_FROM_MEMBER(psz, RTSTRCACHEBIGENTRY, Core.szString);
+ return pBigStr->cchString;
+ }
+ Assert(!((uintptr_t)pStr & 15));
+ return pStr->cchString;
}
RT_EXPORT_SYMBOL(RTStrCacheLength);
+
+RTDECL(bool) RTStrCacheIsRealImpl(void)
+{
+ return true;
+}
+RT_EXPORT_SYMBOL(RTStrCacheIsRealImpl);
+
+
+RTDECL(uint32_t) RTStrCacheGetStats(RTSTRCACHE hStrCache, size_t *pcbStrings, size_t *pcbChunks, size_t *pcbBigEntries,
+ uint32_t *pcHashCollisions, uint32_t *pcHashCollisions2, uint32_t *pcHashInserts,
+ uint32_t *pcRehashes)
+{
+ PRTSTRCACHEINT pThis = hStrCache;
+ RTSTRCACHE_VALID_RETURN_RC(pThis, UINT32_MAX);
+
+ RTCritSectEnter(&pThis->CritSect);
+
+ if (pcbStrings)
+ *pcbStrings = pThis->cbStrings;
+ if (pcbChunks)
+ *pcbChunks = pThis->cbChunks;
+ if (pcbBigEntries)
+ *pcbBigEntries = pThis->cbBigEntries;
+ if (pcHashCollisions)
+ *pcHashCollisions = pThis->cHashCollisions;
+ if (pcHashCollisions2)
+ *pcHashCollisions2 = pThis->cHashCollisions2;
+ if (pcHashInserts)
+ *pcHashInserts = pThis->cHashInserts;
+ if (pcRehashes)
+ *pcRehashes = pThis->cRehashes;
+ uint32_t cStrings = pThis->cStrings;
+
+ RTCritSectLeave(&pThis->CritSect);
+ return cStrings;
+}
+RT_EXPORT_SYMBOL(RTStrCacheRelease);
+
diff --git a/src/VBox/Runtime/common/string/strchr.asm b/src/VBox/Runtime/common/string/strchr.asm
index 7163f28c..e890e9c8 100644
--- a/src/VBox/Runtime/common/string/strchr.asm
+++ b/src/VBox/Runtime/common/string/strchr.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strchr_alias.c b/src/VBox/Runtime/common/string/strchr_alias.c
index 4b4fe4b1..63a9a598 100644
--- a/src/VBox/Runtime/common/string/strchr_alias.c
+++ b/src/VBox/Runtime/common/string/strchr_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strcmp.asm b/src/VBox/Runtime/common/string/strcmp.asm
index 574e5d14..31de02d8 100644
--- a/src/VBox/Runtime/common/string/strcmp.asm
+++ b/src/VBox/Runtime/common/string/strcmp.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strcmp_alias.c b/src/VBox/Runtime/common/string/strcmp_alias.c
index 3c5f7f83..9347aff3 100644
--- a/src/VBox/Runtime/common/string/strcmp_alias.c
+++ b/src/VBox/Runtime/common/string/strcmp_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strcpy.asm b/src/VBox/Runtime/common/string/strcpy.asm
index bee8738b..85f7edec 100644
--- a/src/VBox/Runtime/common/string/strcpy.asm
+++ b/src/VBox/Runtime/common/string/strcpy.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2007 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strcpy.cpp b/src/VBox/Runtime/common/string/strcpy.cpp
index 55da775d..3ea6cf00 100644
--- a/src/VBox/Runtime/common/string/strcpy.cpp
+++ b/src/VBox/Runtime/common/string/strcpy.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strcpy_alias.c b/src/VBox/Runtime/common/string/strcpy_alias.c
index 517cd801..d703d4cd 100644
--- a/src/VBox/Runtime/common/string/strcpy_alias.c
+++ b/src/VBox/Runtime/common/string/strcpy_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strformat.cpp b/src/VBox/Runtime/common/string/strformat.cpp
index 56dc5ec5..335d3033 100644
--- a/src/VBox/Runtime/common/string/strformat.cpp
+++ b/src/VBox/Runtime/common/string/strformat.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strformatnum.cpp b/src/VBox/Runtime/common/string/strformatnum.cpp
index f5b68740..777e8ec7 100644
--- a/src/VBox/Runtime/common/string/strformatnum.cpp
+++ b/src/VBox/Runtime/common/string/strformatnum.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -49,7 +49,7 @@ RTDECL(ssize_t) RTStrFormatU8(char *pszBuf, size_t cbBuf, uint8_t u8Value, unsig
{
char szTmp[64];
cchRet = RTStrFormatNumber(szTmp, u8Value, uiBase, cchWidth, cchPrecision, fFlags);
- if ((size_t)cchRet <= cbBuf)
+ if ((size_t)cchRet < cbBuf)
memcpy(pszBuf, szTmp, cchRet + 1);
else
{
diff --git a/src/VBox/Runtime/common/string/strformatrt.cpp b/src/VBox/Runtime/common/string/strformatrt.cpp
index b5d23853..4dd69f17 100644
--- a/src/VBox/Runtime/common/string/strformatrt.cpp
+++ b/src/VBox/Runtime/common/string/strformatrt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -56,6 +56,121 @@
#include "internal/string.h"
+/**
+ * Helper function to format IPv6 address according to RFC 5952.
+ *
+ * @returns The number of bytes formatted.
+ * @param pfnOutput Pointer to output function.
+ * @param pvArgOutput Argument for the output function.
+ * @param pIpv6Addr IPv6 address
+ */
+static size_t rtstrFormatIPv6(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PCRTNETADDRIPV6 pIpv6Addr)
+{
+ size_t cch = 0; /* result */
+
+ bool fEmbeddedIpv4;
+ size_t cwHexPart;
+ size_t cwZeroRun, cwLongestZeroRun;
+ size_t iZeroStart, iLongestZeroStart;
+ size_t idx;
+
+ Assert(pIpv6Addr != NULL);
+
+ /*
+ * Check for embedded IPv4 address.
+ *
+ * IPv4-compatible - ::11.22.33.44 (obsolete)
+ * IPv4-mapped - ::ffff:11.22.33.44
+ * IPv4-translated - ::ffff:0:11.22.33.44 (RFC 2765)
+ */
+ fEmbeddedIpv4 = false;
+ cwHexPart = RT_ELEMENTS(pIpv6Addr->au16);
+ if (pIpv6Addr->au64[0] == 0
+ && ( (pIpv6Addr->au32[2] == 0
+ && ( pIpv6Addr->au32[3] != 0
+ && pIpv6Addr->au32[3] != RT_H2BE_U32_C(1)))
+ || pIpv6Addr->au32[2] == RT_H2BE_U32_C(0x0000ffff)
+ || pIpv6Addr->au32[2] == RT_H2BE_U32_C(0xffff0000)))
+ {
+ fEmbeddedIpv4 = true;
+ cwHexPart -= 2;
+ }
+
+ cwZeroRun = cwLongestZeroRun = 0;
+ iZeroStart = iLongestZeroStart = -1;
+ for (idx = 0; idx <= cwHexPart; ++idx)
+ {
+ if (idx < cwHexPart && pIpv6Addr->au16[idx] == 0)
+ {
+ if (cwZeroRun == 0)
+ {
+ cwZeroRun = 1;
+ iZeroStart = idx;
+ }
+ else
+ ++cwZeroRun;
+ }
+ else
+ {
+ if (cwZeroRun != 0)
+ {
+ if (cwZeroRun > 1 && cwZeroRun > cwLongestZeroRun)
+ {
+ cwLongestZeroRun = cwZeroRun;
+ iLongestZeroStart = iZeroStart;
+ }
+ cwZeroRun = 0;
+ iZeroStart = -1;
+ }
+ }
+ }
+
+ if (cwLongestZeroRun == 0)
+ {
+ for (idx = 0; idx < cwHexPart; ++idx)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%s%x",
+ idx == 0 ? "" : ":",
+ RT_BE2H_U16(pIpv6Addr->au16[idx]));
+
+ if (fEmbeddedIpv4)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, ":");
+ }
+ else
+ {
+ const size_t iLongestZeroEnd = iLongestZeroStart + cwLongestZeroRun;
+
+ if (iLongestZeroStart == 0)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, ":");
+ else
+ for (idx = 0; idx < iLongestZeroStart; ++idx)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%x:", RT_BE2H_U16(pIpv6Addr->au16[idx]));
+
+ if (iLongestZeroEnd == cwHexPart)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, ":");
+ else
+ {
+ for (idx = iLongestZeroEnd; idx < cwHexPart; ++idx)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ ":%x", RT_BE2H_U16(pIpv6Addr->au16[idx]));
+
+ if (fEmbeddedIpv4)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, ":");
+ }
+ }
+
+ if (fEmbeddedIpv4)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%u.%u.%u.%u",
+ pIpv6Addr->au8[12],
+ pIpv6Addr->au8[13],
+ pIpv6Addr->au8[14],
+ pIpv6Addr->au8[15]);
+
+ return cch;
+}
+
/**
* Callback to format iprt formatting extentions.
@@ -141,7 +256,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
{ STRMEM("Gx"), sizeof(RTGCUINT), 16, RTSF_INT, 0 },
{ STRMEM("Hi"), sizeof(RTHCINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
{ STRMEM("Hp"), sizeof(RTHCPHYS), 16, RTSF_INTW, 0 },
- { STRMEM("Hr"), sizeof(RTGCUINTREG), 16, RTSF_INTW, 0 },
+ { STRMEM("Hr"), sizeof(RTHCUINTREG), 16, RTSF_INTW, 0 },
{ STRMEM("Hu"), sizeof(RTHCUINT), 10, RTSF_INT, 0 },
{ STRMEM("Hv"), sizeof(RTHCPTR), 16, RTSF_INTW, 0 },
{ STRMEM("Hx"), sizeof(RTHCUINT), 16, RTSF_INT, 0 },
@@ -394,24 +509,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
case RTSF_IPV6:
{
if (VALID_PTR(u.pIpv6Addr))
- return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
- "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
- u.pIpv6Addr->au8[0],
- u.pIpv6Addr->au8[1],
- u.pIpv6Addr->au8[2],
- u.pIpv6Addr->au8[3],
- u.pIpv6Addr->au8[4],
- u.pIpv6Addr->au8[5],
- u.pIpv6Addr->au8[6],
- u.pIpv6Addr->au8[7],
- u.pIpv6Addr->au8[8],
- u.pIpv6Addr->au8[9],
- u.pIpv6Addr->au8[10],
- u.pIpv6Addr->au8[11],
- u.pIpv6Addr->au8[12],
- u.pIpv6Addr->au8[13],
- u.pIpv6Addr->au8[14],
- u.pIpv6Addr->au8[15]);
+ return rtstrFormatIPv6(pfnOutput, pvArgOutput, u.pIpv6Addr);
return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
}
@@ -453,42 +551,11 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
case RTNETADDRTYPE_IPV6:
if (u.pNetAddr->uPort == RTNETADDR_PORT_NA)
- return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
- "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
- u.pNetAddr->uAddr.IPv6.au8[0],
- u.pNetAddr->uAddr.IPv6.au8[1],
- u.pNetAddr->uAddr.IPv6.au8[2],
- u.pNetAddr->uAddr.IPv6.au8[3],
- u.pNetAddr->uAddr.IPv6.au8[4],
- u.pNetAddr->uAddr.IPv6.au8[5],
- u.pNetAddr->uAddr.IPv6.au8[6],
- u.pNetAddr->uAddr.IPv6.au8[7],
- u.pNetAddr->uAddr.IPv6.au8[8],
- u.pNetAddr->uAddr.IPv6.au8[9],
- u.pNetAddr->uAddr.IPv6.au8[10],
- u.pNetAddr->uAddr.IPv6.au8[11],
- u.pNetAddr->uAddr.IPv6.au8[12],
- u.pNetAddr->uAddr.IPv6.au8[13],
- u.pNetAddr->uAddr.IPv6.au8[14],
- u.pNetAddr->uAddr.IPv6.au8[15]);
+ return rtstrFormatIPv6(pfnOutput, pvArgOutput, &u.pNetAddr->uAddr.IPv6);
+
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
- "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x %u",
- u.pNetAddr->uAddr.IPv6.au8[0],
- u.pNetAddr->uAddr.IPv6.au8[1],
- u.pNetAddr->uAddr.IPv6.au8[2],
- u.pNetAddr->uAddr.IPv6.au8[3],
- u.pNetAddr->uAddr.IPv6.au8[4],
- u.pNetAddr->uAddr.IPv6.au8[5],
- u.pNetAddr->uAddr.IPv6.au8[6],
- u.pNetAddr->uAddr.IPv6.au8[7],
- u.pNetAddr->uAddr.IPv6.au8[8],
- u.pNetAddr->uAddr.IPv6.au8[9],
- u.pNetAddr->uAddr.IPv6.au8[10],
- u.pNetAddr->uAddr.IPv6.au8[11],
- u.pNetAddr->uAddr.IPv6.au8[12],
- u.pNetAddr->uAddr.IPv6.au8[13],
- u.pNetAddr->uAddr.IPv6.au8[14],
- u.pNetAddr->uAddr.IPv6.au8[15],
+ "[%RTnaipv6]:%u",
+ &u.pNetAddr->uAddr.IPv6,
u.pNetAddr->uPort);
case RTNETADDRTYPE_MAC:
@@ -558,7 +625,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
const char *pszLastSep;
const char *psz = pszLastSep = va_arg(*pArgs, const char *);
if (!VALID_PTR(psz))
- return pfnOutput(pvArgOutput, "<null>", sizeof("<null>") - 1);
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
while ((ch = *psz) != '\0')
{
@@ -602,7 +669,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
const char *pszStart;
const char *psz = pszStart = va_arg(*pArgs, const char *);
if (!VALID_PTR(psz))
- return pfnOutput(pvArgOutput, "<null>", sizeof("<null>") - 1);
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
while ((ch = *psz) != '\0' && ch != '(')
{
@@ -664,7 +731,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
while (off < cchPrecision)
{
int i;
- cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s%0*x %04x:", off ? "\n" : "", sizeof(pu8) * 2, (uintptr_t)pu8, off);
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s%0*p %04x:", off ? "\n" : "", sizeof(pu8) * 2, (uintptr_t)pu8, off);
for (i = 0; i < cchWidth && off + i < cchPrecision ; i++)
cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
off + i < cchPrecision ? !(i & 7) && i ? "-%02x" : " %02x" : " ", pu8[i]);
@@ -707,7 +774,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
}
}
else
- return pfnOutput(pvArgOutput, "<null>", sizeof("<null>") - 1);
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
break;
}
@@ -903,7 +970,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
* If it's a pointer, we'll check if it's valid before going on.
*/
if ((s_aTypes[i].fFlags & RTST_FLAGS_POINTER) && !VALID_PTR(u.pv))
- return pfnOutput(pvArgOutput, "<null>", sizeof("<null>") - 1);
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
/*
* Format the output.
@@ -1098,7 +1165,7 @@ DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, co
REG_OUT_BIT(cr4, X86_CR4_SMXE, "SMXE");
REG_OUT_BIT(cr4, X86_CR4_PCIDE, "PCIDE");
REG_OUT_BIT(cr4, X86_CR4_OSXSAVE, "OSXSAVE");
- REG_OUT_BIT(cr4, X86_CR4_SMEP, "SMPE");
+ REG_OUT_BIT(cr4, X86_CR4_SMEP, "SMEP");
REG_OUT_CLOSE(cr4);
}
else
diff --git a/src/VBox/Runtime/common/string/strformattype.cpp b/src/VBox/Runtime/common/string/strformattype.cpp
index e9e3611a..c37f3b53 100644
--- a/src/VBox/Runtime/common/string/strformattype.cpp
+++ b/src/VBox/Runtime/common/string/strformattype.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -466,9 +466,9 @@ DECLHIDDEN(size_t) rtstrFormatType(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
{
rtstrFormatTypeReadUnlock();
- cch = pfnOutput(pvArgOutput, "<missing:%R[", sizeof("<missing:%R[") - 1);
+ cch = pfnOutput(pvArgOutput, RT_STR_TUPLE("<missing:%R["));
cch += pfnOutput(pvArgOutput, pszType, pszTypeEnd - pszType);
- cch += pfnOutput(pvArgOutput, "]>", sizeof("]>") - 1);
+ cch += pfnOutput(pvArgOutput, RT_STR_TUPLE("]>"));
}
return cch;
diff --git a/src/VBox/Runtime/common/string/strlen.asm b/src/VBox/Runtime/common/string/strlen.asm
index e3ff2f37..b34e5769 100644
--- a/src/VBox/Runtime/common/string/strlen.asm
+++ b/src/VBox/Runtime/common/string/strlen.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2006-2008 Oracle Corporation
+; Copyright (C) 2006-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strlen.cpp b/src/VBox/Runtime/common/string/strlen.cpp
index 173ba2cb..792b040c 100644
--- a/src/VBox/Runtime/common/string/strlen.cpp
+++ b/src/VBox/Runtime/common/string/strlen.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strlen_alias.c b/src/VBox/Runtime/common/string/strlen_alias.c
index 8fab3d16..da471606 100644
--- a/src/VBox/Runtime/common/string/strlen_alias.c
+++ b/src/VBox/Runtime/common/string/strlen_alias.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strncmp.cpp b/src/VBox/Runtime/common/string/strncmp.cpp
index 16faf4b1..24d3fe43 100644
--- a/src/VBox/Runtime/common/string/strncmp.cpp
+++ b/src/VBox/Runtime/common/string/strncmp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strpbrk.cpp b/src/VBox/Runtime/common/string/strpbrk.cpp
index e8d49a81..4e341ee9 100644
--- a/src/VBox/Runtime/common/string/strpbrk.cpp
+++ b/src/VBox/Runtime/common/string/strpbrk.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strprintf.cpp b/src/VBox/Runtime/common/string/strprintf.cpp
index 13bfd4b7..5e96e253 100644
--- a/src/VBox/Runtime/common/string/strprintf.cpp
+++ b/src/VBox/Runtime/common/string/strprintf.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strspace.cpp b/src/VBox/Runtime/common/string/strspace.cpp
index a27a417d..d76c1c19 100644
--- a/src/VBox/Runtime/common/string/strspace.cpp
+++ b/src/VBox/Runtime/common/string/strspace.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strstrip.cpp b/src/VBox/Runtime/common/string/strstrip.cpp
index 3f1b2809..9e930c8a 100644
--- a/src/VBox/Runtime/common/string/strstrip.cpp
+++ b/src/VBox/Runtime/common/string/strstrip.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strtonum.cpp b/src/VBox/Runtime/common/string/strtonum.cpp
index beb9b082..4d49a307 100644
--- a/src/VBox/Runtime/common/string/strtonum.cpp
+++ b/src/VBox/Runtime/common/string/strtonum.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/strversion.cpp b/src/VBox/Runtime/common/string/strversion.cpp
index 7a93bc8d..8c38c864 100644
--- a/src/VBox/Runtime/common/string/strversion.cpp
+++ b/src/VBox/Runtime/common/string/strversion.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/uni.cpp b/src/VBox/Runtime/common/string/uni.cpp
index 1fe613ec..d1bdb8b0 100644
--- a/src/VBox/Runtime/common/string/uni.cpp
+++ b/src/VBox/Runtime/common/string/uni.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/unidata.cpp b/src/VBox/Runtime/common/string/unidata.cpp
index ea5ce4ed..aa2679e2 100644
--- a/src/VBox/Runtime/common/string/unidata.cpp
+++ b/src/VBox/Runtime/common/string/unidata.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/uniread.cpp b/src/VBox/Runtime/common/string/uniread.cpp
index e532482f..01ddd1ca 100644
--- a/src/VBox/Runtime/common/string/uniread.cpp
+++ b/src/VBox/Runtime/common/string/uniread.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -919,7 +919,7 @@ static int Stream1Printf(const char *pszFormat, ...)
if (!g_fQuiet)
cch = vfprintf(stdout, pszFormat, va);
else
- cch = strlen(pszFormat);
+ cch = (int)strlen(pszFormat);
va_end(va);
return cch;
}
diff --git a/src/VBox/Runtime/common/string/utf-16.cpp b/src/VBox/Runtime/common/string/utf-16.cpp
index 3c89a3b0..9386b5d7 100644
--- a/src/VBox/Runtime/common/string/utf-16.cpp
+++ b/src/VBox/Runtime/common/string/utf-16.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/string/utf-8-case.cpp b/src/VBox/Runtime/common/string/utf-8-case.cpp
index 7a0bf2eb..e674944f 100644
--- a/src/VBox/Runtime/common/string/utf-8-case.cpp
+++ b/src/VBox/Runtime/common/string/utf-8-case.cpp
@@ -338,3 +338,82 @@ RTDECL(char *) RTStrToUpper(char *psz)
}
RT_EXPORT_SYMBOL(RTStrToUpper);
+
+RTDECL(bool) RTStrIsCaseFoldable(const char *psz)
+{
+ /*
+ * Loop the code points in the string, checking them one by one until we
+ * find something that can be folded.
+ */
+ RTUNICP uc;
+ do
+ {
+ int rc = RTStrGetCpEx(&psz, &uc);
+ if (RT_SUCCESS(rc))
+ {
+ if (RTUniCpIsFoldable(uc))
+ return true;
+ }
+ else
+ {
+ /* bad encoding, just skip it quietly (uc == RTUNICP_INVALID (!= 0)). */
+ AssertRC(rc);
+ }
+ } while (uc != 0);
+
+ return false;
+}
+RT_EXPORT_SYMBOL(RTStrIsCaseFoldable);
+
+
+RTDECL(bool) RTStrIsUpperCased(const char *psz)
+{
+ /*
+ * Check that there are no lower case chars in the string.
+ */
+ RTUNICP uc;
+ do
+ {
+ int rc = RTStrGetCpEx(&psz, &uc);
+ if (RT_SUCCESS(rc))
+ {
+ if (RTUniCpIsLower(uc))
+ return false;
+ }
+ else
+ {
+ /* bad encoding, just skip it quietly (uc == RTUNICP_INVALID (!= 0)). */
+ AssertRC(rc);
+ }
+ } while (uc != 0);
+
+ return true;
+}
+RT_EXPORT_SYMBOL(RTStrIsUpperCased);
+
+
+RTDECL(bool) RTStrIsLowerCased(const char *psz)
+{
+ /*
+ * Check that there are no lower case chars in the string.
+ */
+ RTUNICP uc;
+ do
+ {
+ int rc = RTStrGetCpEx(&psz, &uc);
+ if (RT_SUCCESS(rc))
+ {
+ if (RTUniCpIsUpper(uc))
+ return false;
+ }
+ else
+ {
+ /* bad encoding, just skip it quietly (uc == RTUNICP_INVALID (!= 0)). */
+ AssertRC(rc);
+ }
+ } while (uc != 0);
+
+ return true;
+}
+RT_EXPORT_SYMBOL(RTStrIsLowerCased);
+
diff --git a/src/VBox/Runtime/common/string/utf-8.cpp b/src/VBox/Runtime/common/string/utf-8.cpp
index 0e486e97..fdeb505e 100644
--- a/src/VBox/Runtime/common/string/utf-8.cpp
+++ b/src/VBox/Runtime/common/string/utf-8.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;