optimization when freeing hash tables. some tuning of buffer allocations

* dict.c hash.c: optimization when freeing hash tables.
* parser.c xmlIO.c include/libxml/tree.h: some tuning of buffer
  allocations
* parser.c parserInternals.c include/libxml/parser.h: keep a
  single allocated block for all the attributes callbacks,
  avoid useless malloc()/free()
* tree.c: do not realloc() when growing a buffer if the buffer
  ain't full, malloc/memcpy/free avoid copying memory.
Daniel
diff --git a/ChangeLog b/ChangeLog
index 2f46709..590df85 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+Tue Aug 19 16:54:18 CEST 2003 Daniel Veillard <daniel@veillard.com>
+
+	* dict.c hash.c: optimization when freeing hash tables.
+	* parser.c xmlIO.c include/libxml/tree.h: some tuning of buffer
+	  allocations
+	* parser.c parserInternals.c include/libxml/parser.h: keep a
+	  single allocated block for all the attributes callbacks,
+	  avoid useless malloc()/free()
+	* tree.c: do not realloc() when growing a buffer if the buffer
+	  ain't full, malloc/memcpy/free avoid copying memory.
+
 Mon Aug 18 18:37:01 CEST 2003 Daniel Veillard <daniel@veillard.com>
 
 	* xmllint.c doc/xmllint.xml doc/xmllint.1: added option
diff --git a/dict.c b/dict.c
index 1002234..eaa4006 100644
--- a/dict.c
+++ b/dict.c
@@ -232,7 +232,7 @@
     if (dict == NULL)
 	return;
     if (dict->dict) {
-	for(i = 0; i < dict->size; i++) {
+	for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
 	    iter = &(dict->dict[i]);
 	    if (iter->valid == 0)
 		continue;
@@ -243,6 +243,7 @@
 		    xmlFree(iter->name);
 		if (!inside_dict)
 		    xmlFree(iter);
+		dict->nbElems--;
 		inside_dict = 0;
 		iter = next;
 	    }
diff --git a/hash.c b/hash.c
index 2a4d000..b4b8656 100644
--- a/hash.c
+++ b/hash.c
@@ -218,11 +218,13 @@
     xmlHashEntryPtr iter;
     xmlHashEntryPtr next;
     int inside_table = 0;
+    int nbElems;
 
     if (table == NULL)
 	return;
     if (table->table) {
-	for(i = 0; i < table->size; i++) {
+	nbElems = table->nbElems;
+	for(i = 0; (i < table->size) && (nbElems > 0); i++) {
 	    iter = &(table->table[i]);
 	    if (iter->valid == 0)
 		continue;
@@ -240,6 +242,7 @@
 		iter->payload = NULL;
 		if (!inside_table)
 		    xmlFree(iter);
+		nbElems--;
 		inside_table = 0;
 		iter = next;
 	    }
diff --git a/include/libxml/parser.h b/include/libxml/parser.h
index b080384..ac3f055 100644
--- a/include/libxml/parser.h
+++ b/include/libxml/parser.h
@@ -236,6 +236,8 @@
     int                recovery;      /* run in recovery mode */
     int                progressive;   /* is this a progressive parsing */
     xmlDictPtr         dict;          /* dictionnary for the parser */
+    const xmlChar *   *atts;         /* array for the attributes callbacks */
+    int                maxatts;       /* the size of the array */
 };
 
 /**
diff --git a/include/libxml/tree.h b/include/libxml/tree.h
index 4ca3c9a..b029ffc 100644
--- a/include/libxml/tree.h
+++ b/include/libxml/tree.h
@@ -50,7 +50,7 @@
  *
  * default buffer size 4000.
  */
-#define BASE_BUFFER_SIZE 4000
+#define BASE_BUFFER_SIZE 4096
 
 /**
  * XML_XML_NAMESPACE:
diff --git a/parser.c b/parser.c
index 535df1e..4eb5265 100644
--- a/parser.c
+++ b/parser.c
@@ -369,8 +369,8 @@
   } while (0)
 
 #define SHRINK if ((ctxt->progressive == 0) &&				\
-		   (ctxt->input->cur - ctxt->input->base > INPUT_CHUNK) && \
-		   (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \
+		   (ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \
+		   (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \
 	xmlSHRINK (ctxt);
 
 static void xmlSHRINK (xmlParserCtxtPtr ctxt) {
@@ -2363,6 +2363,7 @@
     xmlChar limit = 0;
     const xmlChar *in = NULL;
     xmlChar *ret = NULL;
+
     SHRINK;
     GROW;
     in = (xmlChar *) CUR_PTR;
@@ -2412,8 +2413,6 @@
     xmlChar *current = NULL;
     xmlEntityPtr ent;
 
-
-    SHRINK;
     if (NXT(0) == '"') {
 	ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
 	limit = '"';
@@ -6612,9 +6611,9 @@
     const xmlChar *name;
     const xmlChar *attname;
     xmlChar *attvalue;
-    const xmlChar **atts = NULL;
+    const xmlChar **atts = ctxt->atts;
     int nbatts = 0;
-    int maxatts = 0;
+    int maxatts = ctxt->maxatts;
     int i;
 
     if (RAW != '<') return(NULL);
@@ -6670,8 +6669,9 @@
 	     * Add the pair to atts
 	     */
 	    if (atts == NULL) {
-	        maxatts = 10;
-	        atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *));
+	        maxatts = 22; /* allow for 10 attrs by default */
+	        atts = (const xmlChar **)
+		       xmlMalloc(maxatts * sizeof(xmlChar *));
 		if (atts == NULL) {
 		    xmlGenericError(xmlGenericErrorContext,
 			    "malloc of %ld byte failed\n",
@@ -6683,12 +6683,14 @@
 		    ctxt->disableSAX = 1;
 		    goto failed;
 		}
+		ctxt->atts = atts;
+		ctxt->maxatts = maxatts;
 	    } else if (nbatts + 4 > maxatts) {
 	        const xmlChar **n;
 
 	        maxatts *= 2;
 	        n = (const xmlChar **) xmlRealloc((void *) atts,
-						     maxatts * sizeof(xmlChar *));
+					     maxatts * sizeof(const xmlChar *));
 		if (n == NULL) {
 		    xmlGenericError(xmlGenericErrorContext,
 			    "realloc of %ld byte failed\n",
@@ -6701,6 +6703,8 @@
 		    goto failed;
 		}
 		atts = n;
+		ctxt->atts = atts;
+		ctxt->maxatts = maxatts;
 	    }
 	    atts[nbatts++] = attname;
 	    atts[nbatts++] = attvalue;
@@ -6735,6 +6739,7 @@
 	    if (ctxt->recovery == 0) ctxt->disableSAX = 1;
 	    break;
 	}
+	SHRINK;
         GROW;
     }
 
@@ -6742,15 +6747,18 @@
      * SAX: Start of Element !
      */
     if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL) &&
-	(!ctxt->disableSAX))
-        ctxt->sax->startElement(ctxt->userData, name, atts);
+	(!ctxt->disableSAX)) {
+	if (nbatts > 0)
+	    ctxt->sax->startElement(ctxt->userData, name, atts);
+	else
+	    ctxt->sax->startElement(ctxt->userData, name, NULL);
+    }
 
     if (atts != NULL) {
         /* Free only the content strings */
         for (i = 1;i < nbatts;i+=2)
 	    if (atts[i] != NULL)
 	       xmlFree((xmlChar *) atts[i]);
-	xmlFree((void *) atts);
     }
     return(name);
 }
diff --git a/parserInternals.c b/parserInternals.c
index 5c85cbc..ea0a5d0 100644
--- a/parserInternals.c
+++ b/parserInternals.c
@@ -2218,6 +2218,8 @@
     else
         memcpy(ctxt->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
 
+    ctxt->maxatts = 0;
+    ctxt->atts = NULL;
     /* Allocate the Input stack */
     ctxt->inputTab = (xmlParserInputPtr *)
 	        xmlMalloc(5 * sizeof(xmlParserInputPtr));
@@ -2369,6 +2371,7 @@
         xmlFree(ctxt->sax);
     if (ctxt->directory != NULL) xmlFree((char *) ctxt->directory);
     if (ctxt->vctxt.nodeTab != NULL) xmlFree(ctxt->vctxt.nodeTab);
+    if (ctxt->atts != NULL) xmlFree(ctxt->atts);
     if (ctxt->dict != NULL) xmlDictFree(ctxt->dict);
 #ifdef LIBXML_CATALOG_ENABLED
     if (ctxt->catalogs != NULL)
diff --git a/tree.c b/tree.c
index 4dd1027..135c92b 100644
--- a/tree.c
+++ b/tree.c
@@ -6413,9 +6413,21 @@
 
     if (buf->content == NULL)
 	rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
-    else
+    else if (buf->size - buf->use < 100) {
 	rebuf = (xmlChar *) xmlRealloc(buf->content, 
 				       newSize * sizeof(xmlChar));
+   } else {
+        /*
+	 * if we are reallocating a buffer far from being full, it's
+	 * better to make a new allocation and copy only the used range
+	 * and free the old one.
+	 */
+	rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
+	if (rebuf != NULL) {
+	    memcpy(rebuf, buf->content, buf->use);
+	    xmlFree(buf->content);
+	}
+    }
     if (rebuf == NULL) {
         xmlGenericError(xmlGenericErrorContext,
 		"xmlBufferResize : out of memory!\n");
diff --git a/xmlIO.c b/xmlIO.c
index 715cec5..83907f9 100644
--- a/xmlIO.c
+++ b/xmlIO.c
@@ -1574,7 +1574,7 @@
 	return(NULL);
     }
     memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
-    ret->buffer = xmlBufferCreate();
+    ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
     if (ret->buffer == NULL) {
         xmlFree(ret);
 	return(NULL);
@@ -1582,7 +1582,7 @@
     ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
     ret->encoder = xmlGetCharEncodingHandler(enc);
     if (ret->encoder != NULL)
-        ret->raw = xmlBufferCreate();
+        ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
     else
         ret->raw = NULL;
     ret->readcallback = NULL;
@@ -2173,16 +2173,15 @@
     int buffree;
     unsigned int needSize;
 
-    if ((len <= MINLEN) && (len != 4)) 
+    if ((len <= MINLEN) && (len != 4))
         len = MINLEN;
+
     buffree = in->buffer->size - in->buffer->use;
     if (buffree <= 0) {
         xmlGenericError(xmlGenericErrorContext,
 		"xmlParserInputBufferGrow : buffer full !\n");
 	return(0);
     }
-    if (len > buffree) 
-        len = buffree;
 
     needSize = in->buffer->use + len + 1;
     if (needSize > in->buffer->size){