do string allocations in large pools, allowing to find if a string pertain

* dict.c include/libxml/dict.h: do string allocations in large
  pools, allowing to find if a string pertain to a dict quickly
* xmllint.c: fix --stream --repeat --timing
* Makefile.am: the testThreads run output should be seen.
Daniel
diff --git a/ChangeLog b/ChangeLog
index 6bf8561..1bb2fb9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Wed Sep 17 01:07:56 CEST 2003 Daniel Veillard <daniel@veillard.com>
+
+	* dict.c include/libxml/dict.h: do string allocations in large
+	  pools, allowing to find if a string pertain to a dict quickly
+	* xmllint.c: fix --stream --repeat --timing
+	* Makefile.am: the testThreads run output should be seen.
+
 Mon Sep 15 16:46:28 CEST 2003 Daniel Veillard <daniel@veillard.com>
 
 	* SAX2.c include/libxml/parser.h: starting work on reusing the
diff --git a/Makefile.am b/Makefile.am
index 05bb587..6fd1879 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -566,10 +566,10 @@
 	@echo "##"
 	@echo "## Threaded regression tests"
 	@echo "##"
-	-@($(CHECKER) $(top_builddir)/testThreads ; \
+	-($(CHECKER) $(top_builddir)/testThreads ; \
 	   grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0";)
 
-Readertests : testReader$(EXEEXT)
+Readertests : xmllint$(EXEEXT)
 	@(echo > .memdump)
 	@echo "##"
 	@echo "## Reader regression tests"
diff --git a/dict.c b/dict.c
index 380e908..20d1efb 100644
--- a/dict.c
+++ b/dict.c
@@ -40,11 +40,21 @@
 typedef xmlDictEntry *xmlDictEntryPtr;
 struct _xmlDictEntry {
     struct _xmlDictEntry *next;
-    xmlChar *name;
+    const xmlChar *name;
     int len;
     int valid;
 };
 
+typedef struct _xmlDictStrings xmlDictStrings;
+typedef xmlDictStrings *xmlDictStringsPtr;
+struct _xmlDictStrings {
+    xmlDictStringsPtr next;
+    xmlChar *free;
+    xmlChar *end;
+    int size;
+    int nbStrings;
+    xmlChar array[1];
+};
 /*
  * The entire dictionnary
  */
@@ -52,9 +62,59 @@
     struct _xmlDictEntry *dict;
     int size;
     int nbElems;
+    xmlDictStringsPtr strings;
 };
 
 /*
+ * xmlDictAddString:
+ * @dict: the dictionnary
+ * @name: the name of the userdata
+ * @len: the length of the name, if -1 it is recomputed
+ *
+ * Add the string to the array[s]
+ *
+ * Returns the pointer of the local string, or NULL in case of error.
+ */
+static const xmlChar *
+xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
+    xmlDictStringsPtr pool;
+    const xmlChar *ret;
+    int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
+
+    pool = dict->strings;
+    while (pool != NULL) {
+	if (pool->end - pool->free > namelen)
+	    goto found_pool;
+	if (pool->size > size) size = pool->size;
+	pool = pool->next;
+    }
+    /*
+     * Not found, need to allocate
+     */
+    if (pool == NULL) {
+        if (size == 0) size = 1000;
+	else size *= 4; /* exponential growth */
+        if (size < 4 * namelen) 
+	    size = 4 * namelen; /* just in case ! */
+	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
+	if (pool == NULL)
+	    return(NULL);
+	pool->size = size;
+	pool->nbStrings = 0;
+	pool->free = &pool->array[0];
+	pool->end = &pool->array[size];
+	pool->next = dict->strings;
+	dict->strings = pool;
+    }
+found_pool:
+    ret = pool->free;
+    memcpy(pool->free, name, namelen);
+    pool->free += namelen;
+    *(pool->free++) = 0;
+    return(ret);
+}
+
+/*
  * xmlDictComputeKey:
  * Calculate the hash key
  */
@@ -110,6 +170,7 @@
         dict->size = MIN_DICT_SIZE;
 	dict->nbElems = 0;
         dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
+	dict->strings = NULL;
         if (dict->dict) {
   	    memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
   	    return(dict);
@@ -226,6 +287,7 @@
     xmlDictEntryPtr iter;
     xmlDictEntryPtr next;
     int inside_dict = 0;
+    xmlDictStringsPtr pool, nextp;
 
     if (dict == NULL)
 	return;
@@ -237,8 +299,6 @@
 	    inside_dict = 1;
 	    while (iter) {
 		next = iter->next;
-		if (iter->name)
-		    xmlFree(iter->name);
 		if (!inside_dict)
 		    xmlFree(iter);
 		dict->nbElems--;
@@ -249,6 +309,12 @@
 	}
 	xmlFree(dict->dict);
     }
+    pool = dict->strings;
+    while (pool != NULL) {
+        nextp = pool->next;
+	xmlFree(pool);
+	pool = nextp;
+    }
     xmlFree(dict);
 }
 
@@ -294,6 +360,9 @@
 	    return(insert->name);
     }
 
+    ret = xmlDictAddString(dict, name, len);
+    if (ret == NULL)
+        return(NULL);
     if (insert == NULL) {
 	entry = &(dict->dict[key]);
     } else {
@@ -301,8 +370,7 @@
 	if (entry == NULL)
 	     return(NULL);
     }
-
-    ret = entry->name = xmlStrndup(name, len);
+    entry->name = ret;
     entry->len = len;
     entry->next = NULL;
     entry->valid = 1;
@@ -322,6 +390,30 @@
 }
 
 /**
+ * xmlDictOwns:
+ * @dict: the dictionnary
+ * @str: the string
+ *
+ * check if a string is owned by the disctionary
+ *
+ * Returns 1 if true, 0 if false and -1 in case of error
+ * -1 in case of error
+ */
+int
+xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
+    xmlDictStringsPtr pool;
+
+    if ((dict == NULL) || (str == NULL))
+	return(-1);
+    pool = dict->strings;
+    while (pool != NULL) {
+        if ((str >= pool->array) && (str <= pool->free))
+	    return(1);
+	pool = pool->next;
+    }
+    return(0);
+}
+/**
  * xmlDictSize:
  * @dict: the dictionnary
  *
diff --git a/include/libxml/dict.h b/include/libxml/dict.h
index 5b4a59a..551a7d8 100644
--- a/include/libxml/dict.h
+++ b/include/libxml/dict.h
@@ -47,6 +47,9 @@
 			xmlDictLookup	(xmlDictPtr dict,
 		                         const xmlChar *name,
 		                         int len);
+XMLPUBFUN int XMLCALL
+			xmlDictOwns	(xmlDictPtr dict,
+					 const xmlChar *str);
 XMLPUBFUN int XMLCALL			
 			xmlDictSize	(xmlDictPtr dict);
 #ifdef __cplusplus
diff --git a/xmllint.c b/xmllint.c
index 1151bf7..21e3201 100644
--- a/xmllint.c
+++ b/xmllint.c
@@ -618,7 +618,7 @@
 	    xmlTextReaderSetParserProp(reader, XML_PARSER_LOADDTD, 1);
 #ifdef LIBXML_SCHEMAS_ENABLED
 	if (relaxng != NULL) {
-	    if (timing) {
+	    if ((timing) && (!repeat)) {
 		startTimer();
 	    }
 	    ret = xmlTextReaderRelaxNGValidate(reader, relaxng);
@@ -627,7 +627,7 @@
 			"Relax-NG schema %s failed to compile\n", relaxng);
 		relaxng = NULL;
 	    }
-	    if (timing) {
+	    if ((timing) && (!repeat)) {
 		endTimer("Compiling the schemas");
 	    }
 	}
@@ -636,7 +636,7 @@
 	/*
 	 * Process all nodes in sequence
 	 */
-	if (timing) {
+	if ((timing) && (!repeat)) {
 	    startTimer();
 	}
 	ret = xmlTextReaderRead(reader);
@@ -645,7 +645,7 @@
 		processNode(reader);
 	    ret = xmlTextReaderRead(reader);
 	}
-	if (timing) {
+	if ((timing) && (!repeat)) {
 #ifdef LIBXML_SCHEMAS_ENABLED
 	    if ((valid) || (relaxng != NULL))
 #else