Index: gscanner.c
===================================================================
--- gscanner.c	(revision 5741)
+++ gscanner.c	(working copy)
@@ -33,21 +33,21 @@
 
 #include "config.h"
 
-#include	<errno.h>
-#include	<stdlib.h>
-#include	<stdarg.h>
-#include	<string.h>
-#include	<stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
 #ifdef HAVE_UNISTD_H
-#include	<unistd.h>
+#include <unistd.h>
 #endif
 
-#include	"glib.h"
-#include	"gprintfint.h"
-#include        "galias.h"
+#include "glib.h"
+#include "gprintfint.h"
+#include "galias.h"
 
 #ifdef G_OS_WIN32
-#include	<io.h>		/* For _read() */
+#include <io.h>		/* For _read() */
 #endif
 
 /* --- defines --- */
@@ -59,7 +59,7 @@
 	  ((guchar)(c))							\
 	)								\
 )
-#define	READ_BUFFER_SIZE	(4000)
+#define	READ_BUFFER_SIZE	(4096)
 
 
 /* --- typedefs --- */
@@ -122,30 +122,30 @@ static const GScannerConfig g_scanner_co
 
 /* --- prototypes --- */
 static inline
-GScannerKey*	g_scanner_lookup_internal (GScanner	*scanner,
-					   guint	 scope_id,
-					   const gchar	*symbol);
-static gboolean	g_scanner_key_equal	  (gconstpointer v1,
-					   gconstpointer v2);
-static guint	g_scanner_key_hash	  (gconstpointer v);
-static void	g_scanner_get_token_ll	  (GScanner	*scanner,
-					   GTokenType	*token_p,
-					   GTokenValue	*value_p,
-					   guint	*line_p,
-					   guint	*position_p);
-static void	g_scanner_get_token_i	  (GScanner	*scanner,
-					   GTokenType	*token_p,
-					   GTokenValue	*value_p,
-					   guint	*line_p,
-					   guint	*position_p);
-
-static guchar	g_scanner_peek_next_char  (GScanner	*scanner);
-static guchar	g_scanner_get_char	  (GScanner	*scanner,
-					   guint	*line_p,
-					   guint	*position_p);
-static void	g_scanner_msg_handler	  (GScanner	*scanner,
-					   gchar	*message,
-					   gboolean	 is_error);
+GScannerKey*	     g_scanner_lookup_internal (GScanner      *scanner,
+                                                guint          scope_id,
+                                                const gchar   *symbol);
+static gboolean	     g_scanner_key_equal       (gconstpointer  v1,
+                                                gconstpointer  v2);
+static guint	     g_scanner_key_hash	       (gconstpointer  v);
+static void          g_scanner_get_token_ll    (GScanner      *scanner,
+                                                GTokenType    *token_p,
+                                                GTokenValue   *value_p,
+                                                guint         *line_p,
+                                                guint         *position_p);
+static void          g_scanner_get_token_i     (GScanner      *scanner,
+                                                GTokenType    *token_p,
+                                                GTokenValue   *value_p,
+                                                guint         *line_p,
+                                                guint         *position_p);
+
+static guchar        g_scanner_peek_next_char  (GScanner      *scanner);
+static guchar        g_scanner_get_char        (GScanner      *scanner,
+                                                guint         *line_p,
+                                                guint         *position_p);
+static void          g_scanner_msg_handler     (GScanner      *scanner,
+                                                gchar         *message,
+                                                gboolean       is_error);
 
 
 /* --- functions --- */
@@ -168,11 +168,17 @@ g_scanner_char_2_num (guchar	c,
   return -1;
 }
 
 GScanner*
 g_scanner_new (const GScannerConfig *config_templ)
 {
   GScanner *scanner;
-  
+
   if (!config_templ)
     config_templ = &g_scanner_config_template;
   
@@ -233,10 +239,63 @@ g_scanner_new (const GScannerConfig *con
   scanner->scope_id = 0;
   
   scanner->msg_handler = g_scanner_msg_handler;
-  
+
   return scanner;
 }
 
+#define BITS_PER_SLOT       (sizeof (guint32) * 8)
+#define NTH_BIT_OFFSET(x)   ((x) % BITS_PER_SLOT)
+#define NTH_BIT_MASK(x)     (1UL << NTH_BIT_OFFSET (x))
+#define NTH_SLOT(x)         ((x) / BITS_PER_SLOT)
+#define SET_BIT(array, bit) (array[NTH_SLOT (bit)] |= NTH_BIT_MASK (bit))
+#define GET_BIT(array, bit) ((array[NTH_SLOT (bit)] >> NTH_BIT_OFFSET (bit)) & 1)
+
+static inline void
+g_scanner_update_cset_tables (GScanner *scanner)
+{
+  guchar *c;
+
+  if (G_UNLIKELY (scanner->config->cset_skip_characters !=
+                  scanner->cached_skip))
+    {
+      if (scanner->cached_skip)
+        memset (scanner->skip_table, 0, sizeof (scanner->skip_table));
+
+      if (scanner->config->cset_skip_characters)
+        for (c = (guchar *) scanner->config->cset_skip_characters; *c; c++)
+          SET_BIT (scanner->skip_table, *c);
+
+      scanner->cached_skip = scanner->config->cset_skip_characters;
+    }
+
+  if (G_UNLIKELY (scanner->config->cset_identifier_first !=
+                  scanner->cached_first))
+    {
+      if (scanner->cached_first)
+        memset (scanner->first_table, 0, sizeof (scanner->first_table));
+
+      if (scanner->config->cset_identifier_first)
+        for (c = (guchar *) scanner->config->cset_identifier_first; *c; c++)
+          SET_BIT (scanner->first_table, *c);
+
+      scanner->cached_first = scanner->config->cset_identifier_first;
+    }
+
+  if (G_UNLIKELY (scanner->config->cset_identifier_nth !=
+                  scanner->cached_nth))
+    {
+      if (scanner->cached_nth)
+        memset (scanner->nth_table, 0, sizeof (scanner->nth_table));
+
+      if (scanner->config->cset_identifier_nth)
+        for (c = (guchar *) scanner->config->cset_identifier_nth; *c; c++)
+          SET_BIT (scanner->nth_table, *c);
+
+      scanner->cached_nth = scanner->config->cset_identifier_nth;
+    }
+}
+
+
 static inline void
 g_scanner_free_value (GTokenType     *token_p,
 		      GTokenValue     *value_p)
@@ -838,6 +897,8 @@ g_scanner_unexp_token (GScanner		*scanne
   void (*msg_handler)	(GScanner*, const gchar*, ...);
   
   g_return_if_fail (scanner != NULL);
+
+  g_scanner_update_cset_tables (scanner);
   
   if (is_error)
     msg_handler = g_scanner_error;
@@ -865,8 +926,8 @@ g_scanner_unexp_token (GScanner		*scanne
       if (scanner->token >= 1 && scanner->token <= 255)
 	{
 	  if ((scanner->token >= ' ' && scanner->token <= '~') ||
-	      strchr (scanner->config->cset_identifier_first, scanner->token) ||
-	      strchr (scanner->config->cset_identifier_nth, scanner->token))
+	      GET_BIT (scanner->first_table, scanner->token) ||
+	      GET_BIT (scanner->nth_table, scanner->token))
 	    _g_snprintf (token_string, token_string_len, "character `%c'", scanner->token);
 	  else
 	    _g_snprintf (token_string, token_string_len, "character `\\%o'", scanner->token);
@@ -1010,8 +1071,8 @@ g_scanner_unexp_token (GScanner		*scanne
       if (expected_token >= 1 && expected_token <= 255)
 	{
 	  if ((expected_token >= ' ' && expected_token <= '~') ||
-	      strchr (scanner->config->cset_identifier_first, expected_token) ||
-	      strchr (scanner->config->cset_identifier_nth, expected_token))
+	      GET_BIT (scanner->first_table, expected_token) ||
+	      GET_BIT (scanner->nth_table, expected_token))
 	    _g_snprintf (expected_string, expected_string_len, "character `%c'", expected_token);
 	  else
 	    _g_snprintf (expected_string, expected_string_len, "character `\\%o'", expected_token);
@@ -1154,15 +1215,17 @@ g_scanner_get_token_i (GScanner	*scanner
 		       guint		*line_p,
 		       guint		*position_p)
 {
+  g_scanner_update_cset_tables (scanner);
+
   do
     {
       g_scanner_free_value (token_p, value_p);
       g_scanner_get_token_ll (scanner, token_p, value_p, line_p, position_p);
     }
   while (((*token_p > 0 && *token_p < 256) &&
-	  strchr (scanner->config->cset_skip_characters, *token_p)) ||
+	  GET_BIT (scanner->skip_table, *token_p)) ||
 	 (*token_p == G_TOKEN_CHAR &&
-	  strchr (scanner->config->cset_skip_characters, value_p->v_char)) ||
+	  GET_BIT (scanner->skip_table, value_p->v_char)) ||
 	 (*token_p == G_TOKEN_COMMENT_MULTI &&
 	  scanner->config->skip_comment_multi) ||
 	 (*token_p == G_TOKEN_COMMENT_SINGLE &&
@@ -1258,7 +1321,7 @@ g_scanner_get_token_ll	(GScanner	*scanne
        * might interfere with other key chars like slashes or numbers
        */
       if (config->scan_identifier &&
-	  ch && strchr (config->cset_identifier_first, ch))
+	  ch && GET_BIT (scanner->first_table, ch))
 	goto identifier_precedence;
       
       switch (ch)
@@ -1276,7 +1339,7 @@ g_scanner_get_token_ll	(GScanner	*scanne
 	  g_scanner_get_char (scanner, line_p, position_p);
 	  token = G_TOKEN_COMMENT_MULTI;
 	  in_comment_multi = TRUE;
-	  gstring = g_string_new (NULL);
+	  gstring = g_string_sized_new (32);
 	  while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0)
 	    {
 	      if (ch == '*' && g_scanner_peek_next_char (scanner) == '/')
@@ -1296,7 +1359,7 @@ g_scanner_get_token_ll	(GScanner	*scanne
 	    goto default_case;
 	  token = G_TOKEN_STRING;
 	  in_string_sq = TRUE;
-	  gstring = g_string_new (NULL);
+	  gstring = g_string_sized_new (32);
 	  while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0)
 	    {
 	      if (ch == '\'')
@@ -1315,7 +1378,7 @@ g_scanner_get_token_ll	(GScanner	*scanne
 	    goto default_case;
 	  token = G_TOKEN_STRING;
 	  in_string_dq = TRUE;
-	  gstring = g_string_new (NULL);
+	  gstring = g_string_sized_new (32);
 	  while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0)
 	    {
 	      if (ch == '"')
@@ -1477,7 +1540,12 @@ g_scanner_get_token_ll	(GScanner	*scanne
 	  if (token == G_TOKEN_NONE)
 	    token = G_TOKEN_INT;
 	  
-	  gstring = g_string_new (dotted_float ? "0." : "");
+	  gstring = g_string_sized_new (32);
+          if (dotted_float)
+            {
+              g_string_append_c (gstring, '0');
+              g_string_append_c (gstring, '.');
+            }
 	  gstring = g_string_append_c (gstring, ch);
 	  
 	  do /* while (in_number) */
@@ -1621,7 +1689,7 @@ g_scanner_get_token_ll	(GScanner	*scanne
 	    {
 	      token = G_TOKEN_COMMENT_SINGLE;
 	      in_comment_single = TRUE;
-	      gstring = g_string_new (NULL);
+	      gstring = g_string_sized_new (32);
 	      ch = g_scanner_get_char (scanner, line_p, position_p);
 	      while (ch != 0)
 		{
@@ -1641,16 +1709,19 @@ g_scanner_get_token_ll	(GScanner	*scanne
 		in_comment_single = FALSE;
 	    }
 	  else if (config->scan_identifier && ch &&
-		   strchr (config->cset_identifier_first, ch))
+		   GET_BIT (scanner->first_table, ch))
 	    {
+              guchar next_ch;
+
 	    identifier_precedence:
-	      
+
+              next_ch = g_scanner_peek_next_char (scanner);
+
 	      if (config->cset_identifier_nth && ch &&
-		  strchr (config->cset_identifier_nth,
-			  g_scanner_peek_next_char (scanner)))
+		  GET_BIT (scanner->nth_table, next_ch))
 		{
 		  token = G_TOKEN_IDENTIFIER;
-		  gstring = g_string_new (NULL);
+		  gstring = g_string_sized_new (32);
 		  gstring = g_string_append_c (gstring, ch);
 		  do
 		    {
@@ -1658,7 +1729,7 @@ g_scanner_get_token_ll	(GScanner	*scanne
 		      gstring = g_string_append_c (gstring, ch);
 		      ch = g_scanner_peek_next_char (scanner);
 		    }
-		  while (ch && strchr (config->cset_identifier_nth, ch));
+		  while (ch && GET_BIT (scanner->nth_table, ch));
 		  ch = 0;
 		}
 	      else if (config->scan_identifier_1char)
