This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

a new LC_COLLATE locale format



Hi Ulrich,

You mentioned that LC_COLLATE should be size-reduced like LC_CTYPE.
I think that for it to get as small (< 100 KB) more efforts need to be put
in, using some optimizations mentioned in Unicode TR #10.

But a first step is to eliminate the "names" hash table and use a three-level
lookup table here as well. The patch below does this.

                                 old format     new format    improvement

LC_COLLATE locale file size        976440         881128          10%

wcsxfrm on a Unicode string        3.05 msec      2.38 msec       22%
wcsxfrm on an ASCII string         2.76 msec      2.35 msec       15%

As an aside, this patch fixes a bug in locale/C-collate.c: HASH_SIZE and
HASH_LAYERS were set to 0 - it's a wonder than noone got a division by 0.


2000-08-27  Bruno Haible  <haible@clisp.cons.org>

	Support for new LC_COLLATE format.
	* locale/coll-lookup.h: New file.
	* locale/weightwc.h (findidx): When size == 0, call
	collidx_table_lookup.
	* wcsmbs/wcscoll.c: Include coll-lookup.h.
	* wcsmbs/wcsxfrm.c: Likewise.
	* posix/fnmatch.c: Likewise.
	* posix/fnmatch_loop.c (internal_fnwmatch): When size == 0, call
	collseq_table_lookup.
	* locale/programs/3level.h: New file.
	* locale/programs/ld-ctype.c: (wcwidth_table, wctrans_table): Define
	by including "3level.h".
	* locale/programs/ld-collate.c (wchead_table, collidx_table,
	collseq_table): New types, defined by including "3level.h".
	(locale_collate_t): New wcheads_3level, wcseqorder_3level fields.
	(encoding_mask, encoding_byte): Remove.
	(utf8_encode): Use simple shifts instead.
	(collate_finish): When !oldstyle_tables, set plane_size and plane_cnt
	to 0, and initialize and fill wcheads_3level and wcseqorder_3level.
	(collate_output): New local variable tablewc_3level. When
	!oldstyle_tables, set table_size to 0 and names to NULL and fill
	tablewc_3level instead of tablewc. Change format of TABLEWC and
	COLLSEQWC entries written to the file.
	* locale/C-collate.c (collseqwc): Change format.
	(_nl_C_LC_COLLATE): Set HASH_SIZE and HASH_LAYERS to 0, change format
	of COLLSEQWC.
	* locale/Makefile (distribute): Add coll-lookup.h, programs/3level.h.

*** glibc-20000826/locale/coll-lookup.h.bak	Sun Aug 27 13:12:16 2000
--- glibc-20000826/locale/coll-lookup.h	Sun Aug 27 19:31:51 2000
***************
*** 0 ****
--- 1,101 ----
+ /* Copyright (C) 2000 Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+    Contributed by Bruno Haible <haible@clisp.cons.org>, 2000.
+ 
+    The GNU C Library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+ 
+    The GNU C Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+ 
+    You should have received a copy of the GNU Library General Public
+    License along with the GNU C Library; see the file COPYING.LIB.  If not,
+    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ /* Word tables are accessed by cutting wc in three blocks of bits:
+    - the high 32-q-p bits,
+    - the next q bits,
+    - the next p bits.
+ 
+ 	    +------------------+-----+-----+
+      wc  =  +      32-q-p      |  q  |  p  |
+ 	    +------------------+-----+-----+
+ 
+    p and q are variable.  For 16-bit Unicode it is sufficient to
+    choose p and q such that q+p <= 16.
+ 
+    The table contains the following uint32_t words:
+    - q+p,
+    - s = upper exclusive bound for wc >> (q+p),
+    - p,
+    - 2^q-1,
+    - 2^p-1,
+    - 1st-level table: s offsets, pointing into the 2nd-level table,
+    - 2nd-level table: k*2^q offsets, pointing into the 3rd-level table,
+    - 3rd-level table: j*2^p words, each containing 32 bits of data.
+ */
+ 
+ #include <stdint.h>
+ 
+ /* Lookup in a table of int32_t, with default value 0.  */
+ static inline int32_t
+ collidx_table_lookup (const char *table, uint32_t wc)
+ {
+   uint32_t shift1 = ((const uint32_t *) table)[0];
+   uint32_t index1 = wc >> shift1;
+   uint32_t bound = ((const uint32_t *) table)[1];
+   if (index1 < bound)
+     {
+       uint32_t lookup1 = ((const uint32_t *) table)[5 + index1];
+       if (lookup1 != 0)
+ 	{
+ 	  uint32_t shift2 = ((const uint32_t *) table)[2];
+ 	  uint32_t mask2 = ((const uint32_t *) table)[3];
+ 	  uint32_t index2 = (wc >> shift2) & mask2;
+ 	  uint32_t lookup2 = ((const uint32_t *)(table + lookup1))[index2];
+ 	  if (lookup2 != 0)
+ 	    {
+ 	      uint32_t mask3 = ((const uint32_t *) table)[4];
+ 	      uint32_t index3 = wc & mask3;
+ 	      int32_t lookup3 = ((const int32_t *)(table + lookup2))[index3];
+ 
+ 	      return lookup3;
+ 	    }
+ 	}
+     }
+   return 0;
+ }
+ 
+ /* Lookup in a table of uint32_t, with default value 0xffffffff.  */
+ static inline uint32_t
+ collseq_table_lookup (const char *table, uint32_t wc)
+ {
+   uint32_t shift1 = ((const uint32_t *) table)[0];
+   uint32_t index1 = wc >> shift1;
+   uint32_t bound = ((const uint32_t *) table)[1];
+   if (index1 < bound)
+     {
+       uint32_t lookup1 = ((const uint32_t *) table)[5 + index1];
+       if (lookup1 != 0)
+ 	{
+ 	  uint32_t shift2 = ((const uint32_t *) table)[2];
+ 	  uint32_t mask2 = ((const uint32_t *) table)[3];
+ 	  uint32_t index2 = (wc >> shift2) & mask2;
+ 	  uint32_t lookup2 = ((const uint32_t *)(table + lookup1))[index2];
+ 	  if (lookup2 != 0)
+ 	    {
+ 	      uint32_t mask3 = ((const uint32_t *) table)[4];
+ 	      uint32_t index3 = wc & mask3;
+ 	      uint32_t lookup3 = ((const uint32_t *)(table + lookup2))[index3];
+ 
+ 	      return lookup3;
+ 	    }
+ 	}
+     }
+   return ~((uint32_t) 0);
+ }
*** glibc-20000826/locale/weightwc.h.bak	Wed Feb 16 14:12:20 2000
--- glibc-20000826/locale/weightwc.h	Sun Aug 27 19:31:29 2000
***************
*** 24,42 ****
    int_fast32_t i;
    const wint_t *cp;
    wint_t ch;
-   size_t idx;
    size_t cnt = 0;
  
    ch = *(*cpp)++;
!   idx = ch % size;
!   while (names[idx] != ch)
      {
!       if (++cnt == layers)
! 	/* We didn't find the name.  It is case for UNDEFINED.  */
! 	return 0;
!       idx += size;
      }
-   i = table[idx];
  
    if (i >= 0)
      /* This is an index into the weight table.  Cool.  */
--- 24,52 ----
    int_fast32_t i;
    const wint_t *cp;
    wint_t ch;
    size_t cnt = 0;
  
    ch = *(*cpp)++;
!   if (size != 0)
      {
!       /* Old locale format.  */
!       size_t idx;
! 
!       idx = ch % size;
!       while (names[idx] != ch)
! 	{
! 	  if (++cnt == layers)
! 	    /* We didn't find the name.  It is case for UNDEFINED.  */
! 	    return 0;
! 	  idx += size;
! 	}
!       i = table[idx];
!     }
!   else
!     {
!       /* New locale format.  */
!       i = collidx_table_lookup ((const char *) table, ch);
      }
  
    if (i >= 0)
      /* This is an index into the weight table.  Cool.  */
*** glibc-20000826/wcsmbs/wcscoll.c.bak	Fri Aug 25 23:53:44 2000
--- glibc-20000826/wcsmbs/wcscoll.c	Sun Aug 27 13:15:06 2000
***************
*** 18,23 ****
--- 18,24 ----
     Boston, MA 02111-1307, USA.  */
  
  #include <wchar.h>
+ #include "../locale/coll-lookup.h"
  
  #define STRING_TYPE wchar_t
  #define USTRING_TYPE wint_t
*** glibc-20000826/wcsmbs/wcsxfrm.c.bak	Fri Aug 25 23:53:44 2000
--- glibc-20000826/wcsmbs/wcsxfrm.c	Sun Aug 27 13:14:52 2000
***************
*** 18,23 ****
--- 18,24 ----
     Boston, MA 02111-1307, USA.  */
  
  #include <wchar.h>
+ #include "../locale/coll-lookup.h"
  
  #define STRING_TYPE wchar_t
  #define USTRING_TYPE wint_t
*** glibc-20000826/posix/fnmatch.c.bak	Fri Aug 25 23:53:39 2000
--- glibc-20000826/posix/fnmatch.c	Sun Aug 27 13:33:35 2000
***************
*** 54,59 ****
--- 54,60 ----
  #ifdef _LIBC
  # include "../locale/localeinfo.h"
  # include "../locale/elem-hash.h"
+ # include "../locale/coll-lookup.h"
  
  # define CONCAT(a,b) __CONCAT(a,b)
  # define mbsinit __mbsinit
*** glibc-20000826/posix/fnmatch_loop.c.bak	Thu Aug  3 18:04:14 2000
--- glibc-20000826/posix/fnmatch_loop.c	Sun Aug 27 19:32:22 2000
***************
*** 618,661 ****
  			uint32_t fcollseq;
  			uint32_t lcollseq;
  			UCHAR cend = *p++;
- # ifdef WIDE_CHAR_VERSION
- 			int idx;
- 			size_t cnt;
- # endif
  
  # ifdef WIDE_CHAR_VERSION
  			/* Search in the `names' array for the characters.  */
! 			idx = fn % size;
! 			cnt = 0;
! 			while (names[idx] != fn)
  			  {
! 			    if (++cnt == layers)
  			      /* XXX We don't know anything about
  				 the character we are supposed to
  				 match.  This means we are failing.  */
  			      goto range_not_matched;
- 
- 			    idx += size;
  			  }
- 			fcollseq = collseq[idx];
  
  			if (is_seqval)
  			  lcollseq = cold;
  			else
  			  {
! 			    idx = cold % size;
! 			    cnt = 0;
! 			    while (names[idx] != cold)
  			      {
! 				if (++cnt == layers)
  				  {
! 				    idx = -1;
! 				    break;
  				  }
- 				idx += size;
- 			      }
  
! 			    lcollseq = idx == -1 ? 0xffffffff : collseq[idx];
  			  }
  # else
  			fcollseq = collseq[fn];
--- 618,687 ----
  			uint32_t fcollseq;
  			uint32_t lcollseq;
  			UCHAR cend = *p++;
  
  # ifdef WIDE_CHAR_VERSION
  			/* Search in the `names' array for the characters.  */
! 			if (size != 0)
  			  {
! 			    /* Old locale format.  */
! 			    int idx;
! 			    size_t cnt;
! 
! 			    idx = fn % size;
! 			    cnt = 0;
! 			    while (names[idx] != fn)
! 			      {
! 				if (++cnt == layers)
! 				  /* XXX We don't know anything about
! 				     the character we are supposed to
! 				     match.  This means we are failing.  */
! 				  goto range_not_matched;
! 
! 				idx += size;
! 			      }
! 			    fcollseq = collseq[idx];
! 			  }
! 			else
! 			  {
! 			    /* New locale format.  */
! 			    fcollseq =
! 			      collseq_table_lookup ((const char *) collseq, fn);
! 			    if (fcollseq == ~((uint32_t) 0))
  			      /* XXX We don't know anything about
  				 the character we are supposed to
  				 match.  This means we are failing.  */
  			      goto range_not_matched;
  			  }
  
  			if (is_seqval)
  			  lcollseq = cold;
  			else
  			  {
! 			    if (size != 0)
  			      {
! 				/* Old locale format.  */
! 				int idx;
! 				size_t cnt;
! 
! 				idx = cold % size;
! 				cnt = 0;
! 				while (names[idx] != cold)
  				  {
! 				    if (++cnt == layers)
! 				      {
! 					idx = -1;
! 					break;
! 				      }
! 				    idx += size;
  				  }
  
! 				lcollseq =
! 				  idx == -1 ? 0xffffffff : collseq[idx];
! 			      }
! 			    else
! 			      /* New locale format.  */
! 			      lcollseq =
! 				collseq_table_lookup ((const char *) collseq, cold);
  			  }
  # else
  			fcollseq = collseq[fn];
***************
*** 817,838 ****
  			    else
  			      {
  # ifdef WIDE_CHAR_VERSION
! 				idx = cend % size;
! 				cnt = 0;
! 				while (names[idx] != cend)
  				  {
! 				    if (++cnt == layers)
  				      {
! 					/* Hum, no information about the upper
! 					   bound.  The matching succeeds if the
! 					   lower bound is matched exactly.  */
! 					if (idx == -1 && lcollseq != fcollseq)
  					  goto range_not_matched;
  
  					goto matched;
  				      }
  				  }
- 				hcollseq = collseq[idx];
  # else
  				hcollseq = collseq[cend];
  # endif
--- 843,889 ----
  			    else
  			      {
  # ifdef WIDE_CHAR_VERSION
! 				if (size != 0)
  				  {
! 				    /* Old locale format.  */
! 				    int idx;
! 				    size_t cnt;
! 
! 				    idx = cend % size;
! 				    cnt = 0;
! 				    while (names[idx] != cend)
! 				      {
! 					if (++cnt == layers)
! 					  {
! 					    /* Hum, no information about the
! 					       upper bound.  The matching
! 					       succeeds if the lower bound is
! 					       matched exactly.  */
! 					    if (lcollseq != fcollseq)
! 					      goto range_not_matched;
! 
! 					    goto matched;
! 					  }
! 				      }
! 				    hcollseq = collseq[idx];
! 				  }
! 				else
! 				  {
! 				    /* New locale format.  */
! 				    hcollseq =
! 				      collseq_table_lookup ((const char *) collseq, cend);
! 				    if (hcollseq == ~((uint32_t) 0))
  				      {
! 					/* Hum, no information about the
! 					   upper bound.  The matching succeeds
! 					   if the lower bound is matched
! 					   exactly.  */
! 					if (lcollseq != fcollseq)
  					  goto range_not_matched;
  
  					goto matched;
  				      }
  				  }
  # else
  				hcollseq = collseq[cend];
  # endif
*** glibc-20000826/locale/programs/3level.h.bak	Sun Aug 27 14:39:05 2000
--- glibc-20000826/locale/programs/3level.h	Sun Aug 27 19:30:48 2000
***************
*** 0 ****
--- 1,321 ----
+ /* Copyright (C) 2000 Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+    Contributed by Bruno Haible <haible@clisp.cons.org>, 2000.
+ 
+    The GNU C Library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+ 
+    The GNU C Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+ 
+    You should have received a copy of the GNU Library General Public
+    License along with the GNU C Library; see the file COPYING.LIB.  If not,
+    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ /* Construction of sparse 3-level tables.
+    See wchar-lookup.h or coll-lookup.h for their structure and the
+    meaning of p and q.
+ 
+    Before including this file, set
+      TABLE        to the name of the structure to be defined
+      ELEMENT      to the type of every entry
+      DEFAULT      to the default value for empty entries
+      ITERATE      if you want the TABLE_iterate function to be defined
+      NO_FINALIZE  if you don't want the TABLE_finalize function to be defined
+ 
+    This will define
+ 
+      struct TABLE;
+      void TABLE_init (struct TABLE *t);
+      ELEMENT TABLE_get (struct TABLE *t, uint32_t wc);
+      void TABLE_add (struct TABLE *t, uint32_t wc, ELEMENT value);
+      void TABLE_iterate (struct TABLE *t,
+ 			 void (*fn) (uint32_t wc, ELEMENT value));
+      void TABLE_finalize (struct TABLE *t);
+ */
+ 
+ #define CONCAT(a,b) CONCAT1(a,b)
+ #define CONCAT1(a,b) a##b
+ 
+ struct TABLE
+ {
+   /* Parameters.  */
+   unsigned int p;
+   unsigned int q;
+   /* Working representation.  */
+   size_t level1_alloc;
+   size_t level1_size;
+   uint32_t *level1;
+   size_t level2_alloc;
+   size_t level2_size;
+   uint32_t *level2;
+   size_t level3_alloc;
+   size_t level3_size;
+   ELEMENT *level3;
+   /* Compressed representation.  */
+   size_t result_size;
+   char *result;
+ };
+ 
+ /* Initialize.  Assumes t->p and t->q have already been set.  */
+ static inline void
+ CONCAT(TABLE,_init) (struct TABLE *t)
+ {
+   t->level1_alloc = t->level1_size = 0;
+   t->level2_alloc = t->level2_size = 0;
+   t->level3_alloc = t->level3_size = 0;
+ }
+ 
+ /* Retrieve an entry.  */
+ static inline ELEMENT
+ CONCAT(TABLE,_get) (struct TABLE *t, uint32_t wc)
+ {
+   uint32_t index1 = wc >> (t->q + t->p);
+   if (index1 < t->level1_size)
+     {
+       uint32_t lookup1 = t->level1[index1];
+       if (lookup1 != ~((uint32_t) 0))
+ 	{
+ 	  uint32_t index2 = ((wc >> t->p) & ((1 << t->q) - 1))
+ 			    + (lookup1 << t->q);
+ 	  uint32_t lookup2 = t->level2[index2];
+ 	  if (lookup2 != ~((uint32_t) 0))
+ 	    {
+ 	      uint32_t index3 = (wc & ((1 << t->p) - 1))
+ 				+ (lookup2 << t->p);
+ 	      ELEMENT lookup3 = t->level3[index3];
+ 
+ 	      return lookup3;
+ 	    }
+ 	}
+     }
+   return DEFAULT;
+ }
+ 
+ /* Add one entry.  */
+ static void
+ CONCAT(TABLE,_add) (struct TABLE *t, uint32_t wc, ELEMENT value)
+ {
+   uint32_t index1 = wc >> (t->q + t->p);
+   uint32_t index2 = (wc >> t->p) & ((1 << t->q) - 1);
+   uint32_t index3 = wc & ((1 << t->p) - 1);
+   size_t i, i1, i2;
+ 
+   if (value == CONCAT(TABLE,_get) (t, wc))
+     return;
+ 
+   if (index1 >= t->level1_size)
+     {
+       if (index1 >= t->level1_alloc)
+ 	{
+ 	  size_t alloc = 2 * t->level1_alloc;
+ 	  if (alloc <= index1)
+ 	    alloc = index1 + 1;
+ 	  t->level1 = (t->level1_alloc > 0
+ 		       ? (uint32_t *) xrealloc ((char *) t->level1,
+ 						alloc * sizeof (uint32_t))
+ 		       : (uint32_t *) xmalloc (alloc * sizeof (uint32_t)));
+ 	  t->level1_alloc = alloc;
+ 	}
+       while (index1 >= t->level1_size)
+ 	t->level1[t->level1_size++] = ~((uint32_t) 0);
+     }
+ 
+   if (t->level1[index1] == ~((uint32_t) 0))
+     {
+       if (t->level2_size == t->level2_alloc)
+ 	{
+ 	  size_t alloc = 2 * t->level2_alloc + 1;
+ 	  t->level2 = (t->level2_alloc > 0
+ 		       ? (uint32_t *) xrealloc ((char *) t->level2,
+ 						(alloc << t->q) * sizeof (uint32_t))
+ 		       : (uint32_t *) xmalloc ((alloc << t->q) * sizeof (uint32_t)));
+ 	  t->level2_alloc = alloc;
+ 	}
+       i1 = t->level2_size << t->q;
+       i2 = (t->level2_size + 1) << t->q;
+       for (i = i1; i < i2; i++)
+ 	t->level2[i] = ~((uint32_t) 0);
+       t->level1[index1] = t->level2_size++;
+     }
+ 
+   index2 += t->level1[index1] << t->q;
+ 
+   if (t->level2[index2] == ~((uint32_t) 0))
+     {
+       if (t->level3_size == t->level3_alloc)
+ 	{
+ 	  size_t alloc = 2 * t->level3_alloc + 1;
+ 	  t->level3 = (t->level3_alloc > 0
+ 		       ? (ELEMENT *) xrealloc ((char *) t->level3,
+ 					       (alloc << t->p) * sizeof (ELEMENT))
+ 		       : (ELEMENT *) xmalloc ((alloc << t->p) * sizeof (ELEMENT)));
+ 	  t->level3_alloc = alloc;
+ 	}
+       i1 = t->level3_size << t->p;
+       i2 = (t->level3_size + 1) << t->p;
+       for (i = i1; i < i2; i++)
+ 	t->level3[i] = DEFAULT;
+       t->level2[index2] = t->level3_size++;
+     }
+ 
+   index3 += t->level2[index2] << t->p;
+ 
+   t->level3[index3] = value;
+ }
+ 
+ #ifdef ITERATE
+ /* Apply a function to all entries in the table.  */
+ static void
+ CONCAT(TABLE,_iterate) (struct TABLE *t,
+ 			void (*fn) (uint32_t wc, ELEMENT value))
+ {
+   uint32_t index1;
+   for (index1 = 0; index1 < t->level1_size; index1++)
+     {
+       uint32_t lookup1 = t->level1[index1];
+       if (lookup1 != ~((uint32_t) 0))
+ 	{
+ 	  uint32_t lookup1_shifted = lookup1 << t->q;
+ 	  uint32_t index2;
+ 	  for (index2 = 0; index2 < (1 << t->q); index2++)
+ 	    {
+ 	      uint32_t lookup2 = t->level2[index2 + lookup1_shifted];
+ 	      if (lookup2 != ~((uint32_t) 0))
+ 		{
+ 		  uint32_t lookup2_shifted = lookup2 << t->p;
+ 		  uint32_t index3;
+ 		  for (index3 = 0; index3 < (1 << t->p); index3++)
+ 		    {
+ 		      ELEMENT lookup3 = t->level3[index3 + lookup2_shifted];
+ 		      if (lookup3 != DEFAULT)
+ 			fn ((((index1 << t->q) + index2) << t->p) + index3,
+ 			    lookup3);
+ 		    }
+ 		}
+ 	    }
+ 	}
+     }
+ }
+ #endif
+ 
+ #ifndef NO_FINALIZE
+ /* Finalize and shrink.  */
+ static void
+ CONCAT(TABLE,_finalize) (struct TABLE *t)
+ {
+   size_t i, j, k;
+   uint32_t reorder3[t->level3_size];
+   uint32_t reorder2[t->level2_size];
+   uint32_t level1_offset, level2_offset, level3_offset, last_offset;
+ 
+   /* Uniquify level3 blocks.  */
+   k = 0;
+   for (j = 0; j < t->level3_size; j++)
+     {
+       for (i = 0; i < k; i++)
+ 	if (memcmp (&t->level3[i << t->p], &t->level3[j << t->p],
+ 		    (1 << t->p) * sizeof (ELEMENT)) == 0)
+ 	  break;
+       /* Relocate block j to block i.  */
+       reorder3[j] = i;
+       if (i == k)
+ 	{
+ 	  if (i != j)
+ 	    memcpy (&t->level3[i << t->p], &t->level3[j << t->p],
+ 		    (1 << t->p) * sizeof (ELEMENT));
+ 	  k++;
+ 	}
+     }
+   t->level3_size = k;
+ 
+   for (i = 0; i < (t->level2_size << t->q); i++)
+     if (t->level2[i] != ~((uint32_t) 0))
+       t->level2[i] = reorder3[t->level2[i]];
+ 
+   /* Uniquify level2 blocks.  */
+   k = 0;
+   for (j = 0; j < t->level2_size; j++)
+     {
+       for (i = 0; i < k; i++)
+ 	if (memcmp (&t->level2[i << t->q], &t->level2[j << t->q],
+ 		    (1 << t->q) * sizeof (uint32_t)) == 0)
+ 	  break;
+       /* Relocate block j to block i.  */
+       reorder2[j] = i;
+       if (i == k)
+ 	{
+ 	  if (i != j)
+ 	    memcpy (&t->level2[i << t->q], &t->level2[j << t->q],
+ 		    (1 << t->q) * sizeof (uint32_t));
+ 	  k++;
+ 	}
+     }
+   t->level2_size = k;
+ 
+   for (i = 0; i < t->level1_size; i++)
+     if (t->level1[i] != ~((uint32_t) 0))
+       t->level1[i] = reorder2[t->level1[i]];
+ 
+   /* Create and fill the resulting compressed representation.  */
+   last_offset =
+     5 * sizeof (uint32_t)
+     + t->level1_size * sizeof (uint32_t)
+     + (t->level2_size << t->q) * sizeof (uint32_t)
+     + (t->level3_size << t->p) * sizeof (ELEMENT);
+   t->result_size = (last_offset + 3) & ~3ul;
+   t->result = (char *) xmalloc (t->result_size);
+ 
+   level1_offset =
+     5 * sizeof (uint32_t);
+   level2_offset =
+     5 * sizeof (uint32_t)
+     + t->level1_size * sizeof (uint32_t);
+   level3_offset =
+     5 * sizeof (uint32_t)
+     + t->level1_size * sizeof (uint32_t)
+     + (t->level2_size << t->q) * sizeof (uint32_t);
+ 
+   ((uint32_t *) t->result)[0] = t->q + t->p;
+   ((uint32_t *) t->result)[1] = t->level1_size;
+   ((uint32_t *) t->result)[2] = t->p;
+   ((uint32_t *) t->result)[3] = (1 << t->q) - 1;
+   ((uint32_t *) t->result)[4] = (1 << t->p) - 1;
+ 
+   for (i = 0; i < t->level1_size; i++)
+     ((uint32_t *) (t->result + level1_offset))[i] =
+       (t->level1[i] == ~((uint32_t) 0)
+        ? 0
+        : (t->level1[i] << t->q) * sizeof (uint32_t) + level2_offset);
+ 
+   for (i = 0; i < (t->level2_size << t->q); i++)
+     ((uint32_t *) (t->result + level2_offset))[i] =
+       (t->level2[i] == ~((uint32_t) 0)
+        ? 0
+        : (t->level2[i] << t->p) * sizeof (ELEMENT) + level3_offset);
+ 
+   for (i = 0; i < (t->level3_size << t->p); i++)
+     ((ELEMENT *) (t->result + level3_offset))[i] = t->level3[i];
+ 
+   if (last_offset < t->result_size)
+     memset (t->result + last_offset, 0, t->result_size - last_offset);
+ 
+   if (t->level1_alloc > 0)
+     free (t->level1);
+   if (t->level2_alloc > 0)
+     free (t->level2);
+   if (t->level3_alloc > 0)
+     free (t->level3);
+ }
+ #endif
+ 
+ #undef TABLE
+ #undef ELEMENT
+ #undef DEFAULT
+ #undef ITERATE
+ #undef NO_FINALIZE
*** glibc-20000826/locale/programs/ld-ctype.c.bak	Fri Aug 25 23:52:58 2000
--- glibc-20000826/locale/programs/ld-ctype.c	Sun Aug 27 15:27:38 2000
***************
*** 3582,4054 ****
      free (t->level3);
  }
  
! struct wcwidth_table
! {
!   /* Parameters.  */
!   unsigned int p;
!   unsigned int q;
!   /* Working representation.  */
!   size_t level1_alloc;
!   size_t level1_size;
!   uint32_t *level1;
!   size_t level2_alloc;
!   size_t level2_size;
!   uint32_t *level2;
!   size_t level3_alloc;
!   size_t level3_size;
!   uint8_t *level3;
!   /* Compressed representation.  */
!   size_t result_size;
!   char *result;
! };
! 
! /* Initialize.  Assumes t->p and t->q have already been set.  */
! static inline void
! wcwidth_table_init (struct wcwidth_table *t)
! {
!   t->level1_alloc = t->level1_size = 0;
!   t->level2_alloc = t->level2_size = 0;
!   t->level3_alloc = t->level3_size = 0;
! }
! 
! /* Retrieve an entry.  */
! static inline uint8_t
! wcwidth_table_get (struct wcwidth_table *t, uint32_t wc)
! {
!   uint32_t index1 = wc >> (t->q + t->p);
!   if (index1 < t->level1_size)
!     {
!       uint32_t lookup1 = t->level1[index1];
!       if (lookup1 != ~((uint32_t) 0))
! 	{
! 	  uint32_t index2 = ((wc >> t->p) & ((1 << t->q) - 1))
! 			    + (lookup1 << t->q);
! 	  uint32_t lookup2 = t->level2[index2];
! 	  if (lookup2 != ~((uint32_t) 0))
! 	    {
! 	      uint32_t index3 = (wc & ((1 << t->p) - 1))
! 				+ (lookup2 << t->p);
! 	      uint8_t lookup3 = t->level3[index3];
! 
! 	      return lookup3;
! 	    }
! 	}
!     }
!   return 0xff;
! }
! 
! /* Add one entry.  */
! static void
! wcwidth_table_add (struct wcwidth_table *t, uint32_t wc, uint8_t width)
! {
!   uint32_t index1 = wc >> (t->q + t->p);
!   uint32_t index2 = (wc >> t->p) & ((1 << t->q) - 1);
!   uint32_t index3 = wc & ((1 << t->p) - 1);
!   size_t i, i1, i2;
! 
!   if (width == wcwidth_table_get (t, wc))
!     return;
! 
!   if (index1 >= t->level1_size)
!     {
!       if (index1 >= t->level1_alloc)
! 	{
! 	  size_t alloc = 2 * t->level1_alloc;
! 	  if (alloc <= index1)
! 	    alloc = index1 + 1;
! 	  t->level1 = (t->level1_alloc > 0
! 		       ? (uint32_t *) xrealloc ((char *) t->level1,
! 						alloc * sizeof (uint32_t))
! 		       : (uint32_t *) xmalloc (alloc * sizeof (uint32_t)));
! 	  t->level1_alloc = alloc;
! 	}
!       while (index1 >= t->level1_size)
! 	t->level1[t->level1_size++] = ~((uint32_t) 0);
!     }
! 
!   if (t->level1[index1] == ~((uint32_t) 0))
!     {
!       if (t->level2_size == t->level2_alloc)
! 	{
! 	  size_t alloc = 2 * t->level2_alloc + 1;
! 	  t->level2 = (t->level2_alloc > 0
! 		       ? (uint32_t *) xrealloc ((char *) t->level2,
! 						(alloc << t->q) * sizeof (uint32_t))
! 		       : (uint32_t *) xmalloc ((alloc << t->q) * sizeof (uint32_t)));
! 	  t->level2_alloc = alloc;
! 	}
!       i1 = t->level2_size << t->q;
!       i2 = (t->level2_size + 1) << t->q;
!       for (i = i1; i < i2; i++)
! 	t->level2[i] = ~((uint32_t) 0);
!       t->level1[index1] = t->level2_size++;
!     }
! 
!   index2 += t->level1[index1] << t->q;
! 
!   if (t->level2[index2] == ~((uint32_t) 0))
!     {
!       if (t->level3_size == t->level3_alloc)
! 	{
! 	  size_t alloc = 2 * t->level3_alloc + 1;
! 	  t->level3 = (t->level3_alloc > 0
! 		       ? (uint8_t *) xrealloc ((char *) t->level3,
! 					       (alloc << t->p) * sizeof (uint8_t))
! 		       : (uint8_t *) xmalloc ((alloc << t->p) * sizeof (uint8_t)));
! 	  t->level3_alloc = alloc;
! 	}
!       i1 = t->level3_size << t->p;
!       i2 = (t->level3_size + 1) << t->p;
!       for (i = i1; i < i2; i++)
! 	t->level3[i] = 0xff;
!       t->level2[index2] = t->level3_size++;
!     }
! 
!   index3 += t->level2[index2] << t->p;
! 
!   t->level3[index3] = width;
! }
! 
! /* Finalize and shrink.  */
! static void
! wcwidth_table_finalize (struct wcwidth_table *t)
! {
!   size_t i, j, k;
!   uint32_t reorder3[t->level3_size];
!   uint32_t reorder2[t->level2_size];
!   uint32_t level1_offset, level2_offset, level3_offset, last_offset;
! 
!   /* Uniquify level3 blocks.  */
!   k = 0;
!   for (j = 0; j < t->level3_size; j++)
!     {
!       for (i = 0; i < k; i++)
! 	if (memcmp (&t->level3[i << t->p], &t->level3[j << t->p],
! 		    (1 << t->p) * sizeof (uint8_t)) == 0)
! 	  break;
!       /* Relocate block j to block i.  */
!       reorder3[j] = i;
!       if (i == k)
! 	{
! 	  if (i != j)
! 	    memcpy (&t->level3[i << t->p], &t->level3[j << t->p],
! 		    (1 << t->p) * sizeof (uint8_t));
! 	  k++;
! 	}
!     }
!   t->level3_size = k;
! 
!   for (i = 0; i < (t->level2_size << t->q); i++)
!     if (t->level2[i] != ~((uint32_t) 0))
!       t->level2[i] = reorder3[t->level2[i]];
! 
!   /* Uniquify level2 blocks.  */
!   k = 0;
!   for (j = 0; j < t->level2_size; j++)
!     {
!       for (i = 0; i < k; i++)
! 	if (memcmp (&t->level2[i << t->q], &t->level2[j << t->q],
! 		    (1 << t->q) * sizeof (uint32_t)) == 0)
! 	  break;
!       /* Relocate block j to block i.  */
!       reorder2[j] = i;
!       if (i == k)
! 	{
! 	  if (i != j)
! 	    memcpy (&t->level2[i << t->q], &t->level2[j << t->q],
! 		    (1 << t->q) * sizeof (uint32_t));
! 	  k++;
! 	}
!     }
!   t->level2_size = k;
! 
!   for (i = 0; i < t->level1_size; i++)
!     if (t->level1[i] != ~((uint32_t) 0))
!       t->level1[i] = reorder2[t->level1[i]];
! 
!   /* Create and fill the resulting compressed representation.  */
!   last_offset =
!     5 * sizeof (uint32_t)
!     + t->level1_size * sizeof (uint32_t)
!     + (t->level2_size << t->q) * sizeof (uint32_t)
!     + (t->level3_size << t->p) * sizeof (uint8_t);
!   t->result_size = (last_offset + 3) & ~3ul;
!   t->result = (char *) xmalloc (t->result_size);
! 
!   level1_offset =
!     5 * sizeof (uint32_t);
!   level2_offset =
!     5 * sizeof (uint32_t)
!     + t->level1_size * sizeof (uint32_t);
!   level3_offset =
!     5 * sizeof (uint32_t)
!     + t->level1_size * sizeof (uint32_t)
!     + (t->level2_size << t->q) * sizeof (uint32_t);
! 
!   ((uint32_t *) t->result)[0] = t->q + t->p;
!   ((uint32_t *) t->result)[1] = t->level1_size;
!   ((uint32_t *) t->result)[2] = t->p;
!   ((uint32_t *) t->result)[3] = (1 << t->q) - 1;
!   ((uint32_t *) t->result)[4] = (1 << t->p) - 1;
! 
!   for (i = 0; i < t->level1_size; i++)
!     ((uint32_t *) (t->result + level1_offset))[i] =
!       (t->level1[i] == ~((uint32_t) 0)
!        ? 0
!        : (t->level1[i] << t->q) * sizeof (uint32_t) + level2_offset);
! 
!   for (i = 0; i < (t->level2_size << t->q); i++)
!     ((uint32_t *) (t->result + level2_offset))[i] =
!       (t->level2[i] == ~((uint32_t) 0)
!        ? 0
!        : (t->level2[i] << t->p) * sizeof (uint8_t) + level3_offset);
! 
!   for (i = 0; i < (t->level3_size << t->p); i++)
!     ((uint8_t *) (t->result + level3_offset))[i] = t->level3[i];
! 
!   if (last_offset < t->result_size)
!     memset (t->result + last_offset, 0, t->result_size - last_offset);
! 
!   if (t->level1_alloc > 0)
!     free (t->level1);
!   if (t->level2_alloc > 0)
!     free (t->level2);
!   if (t->level3_alloc > 0)
!     free (t->level3);
! }
! 
! struct wctrans_table
! {
!   /* Parameters.  */
!   unsigned int p;
!   unsigned int q;
!   /* Working representation.  */
!   size_t level1_alloc;
!   size_t level1_size;
!   uint32_t *level1;
!   size_t level2_alloc;
!   size_t level2_size;
!   uint32_t *level2;
!   size_t level3_alloc;
!   size_t level3_size;
!   int32_t *level3;
!   /* Compressed representation.  */
!   size_t result_size;
!   char *result;
! };
! 
! /* Initialize.  Assumes t->p and t->q have already been set.  */
  static inline void
- wctrans_table_init (struct wctrans_table *t)
- {
-   t->level1_alloc = t->level1_size = 0;
-   t->level2_alloc = t->level2_size = 0;
-   t->level3_alloc = t->level3_size = 0;
- }
- 
- /* Retrieve an entry.  */
- static inline uint32_t
- wctrans_table_get (struct wctrans_table *t, uint32_t wc)
- {
-   uint32_t index1 = wc >> (t->q + t->p);
-   if (index1 < t->level1_size)
-     {
-       uint32_t lookup1 = t->level1[index1];
-       if (lookup1 != ~((uint32_t) 0))
- 	{
- 	  uint32_t index2 = ((wc >> t->p) & ((1 << t->q) - 1))
- 			    + (lookup1 << t->q);
- 	  uint32_t lookup2 = t->level2[index2];
- 	  if (lookup2 != ~((uint32_t) 0))
- 	    {
- 	      uint32_t index3 = (wc & ((1 << t->p) - 1))
- 				+ (lookup2 << t->p);
- 	      int32_t lookup3 = t->level3[index3];
- 
- 	      return wc + lookup3;
- 	    }
- 	}
-     }
-   return wc;
- }
- 
- /* Add one entry.  */
- static void
  wctrans_table_add (struct wctrans_table *t, uint32_t wc, uint32_t mapped_wc)
  {
!   uint32_t index1 = wc >> (t->q + t->p);
!   uint32_t index2 = (wc >> t->p) & ((1 << t->q) - 1);
!   uint32_t index3 = wc & ((1 << t->p) - 1);
!   int32_t value;
!   size_t i, i1, i2;
! 
!   if (mapped_wc == wctrans_table_get (t, wc))
!     return;
! 
!   value = (int32_t) mapped_wc - (int32_t) wc;
! 
!   if (index1 >= t->level1_size)
!     {
!       if (index1 >= t->level1_alloc)
! 	{
! 	  size_t alloc = 2 * t->level1_alloc;
! 	  if (alloc <= index1)
! 	    alloc = index1 + 1;
! 	  t->level1 = (t->level1_alloc > 0
! 		       ? (uint32_t *) xrealloc ((char *) t->level1,
! 						alloc * sizeof (uint32_t))
! 		       : (uint32_t *) xmalloc (alloc * sizeof (uint32_t)));
! 	  t->level1_alloc = alloc;
! 	}
!       while (index1 >= t->level1_size)
! 	t->level1[t->level1_size++] = ~((uint32_t) 0);
!     }
! 
!   if (t->level1[index1] == ~((uint32_t) 0))
!     {
!       if (t->level2_size == t->level2_alloc)
! 	{
! 	  size_t alloc = 2 * t->level2_alloc + 1;
! 	  t->level2 = (t->level2_alloc > 0
! 		       ? (uint32_t *) xrealloc ((char *) t->level2,
! 						(alloc << t->q) * sizeof (uint32_t))
! 		       : (uint32_t *) xmalloc ((alloc << t->q) * sizeof (uint32_t)));
! 	  t->level2_alloc = alloc;
! 	}
!       i1 = t->level2_size << t->q;
!       i2 = (t->level2_size + 1) << t->q;
!       for (i = i1; i < i2; i++)
! 	t->level2[i] = ~((uint32_t) 0);
!       t->level1[index1] = t->level2_size++;
!     }
! 
!   index2 += t->level1[index1] << t->q;
! 
!   if (t->level2[index2] == ~((uint32_t) 0))
!     {
!       if (t->level3_size == t->level3_alloc)
! 	{
! 	  size_t alloc = 2 * t->level3_alloc + 1;
! 	  t->level3 = (t->level3_alloc > 0
! 		       ? (int32_t *) xrealloc ((char *) t->level3,
! 					       (alloc << t->p) * sizeof (int32_t))
! 		       : (int32_t *) xmalloc ((alloc << t->p) * sizeof (int32_t)));
! 	  t->level3_alloc = alloc;
! 	}
!       i1 = t->level3_size << t->p;
!       i2 = (t->level3_size + 1) << t->p;
!       for (i = i1; i < i2; i++)
! 	t->level3[i] = 0;
!       t->level2[index2] = t->level3_size++;
!     }
! 
!   index3 += t->level2[index2] << t->p;
! 
!   t->level3[index3] = value;
! }
! 
! /* Finalize and shrink.  */
! static void
! wctrans_table_finalize (struct wctrans_table *t)
! {
!   size_t i, j, k;
!   uint32_t reorder3[t->level3_size];
!   uint32_t reorder2[t->level2_size];
!   uint32_t level1_offset, level2_offset, level3_offset;
! 
!   /* Uniquify level3 blocks.  */
!   k = 0;
!   for (j = 0; j < t->level3_size; j++)
!     {
!       for (i = 0; i < k; i++)
! 	if (memcmp (&t->level3[i << t->p], &t->level3[j << t->p],
! 		    (1 << t->p) * sizeof (int32_t)) == 0)
! 	  break;
!       /* Relocate block j to block i.  */
!       reorder3[j] = i;
!       if (i == k)
! 	{
! 	  if (i != j)
! 	    memcpy (&t->level3[i << t->p], &t->level3[j << t->p],
! 		    (1 << t->p) * sizeof (int32_t));
! 	  k++;
! 	}
!     }
!   t->level3_size = k;
! 
!   for (i = 0; i < (t->level2_size << t->q); i++)
!     if (t->level2[i] != ~((uint32_t) 0))
!       t->level2[i] = reorder3[t->level2[i]];
! 
!   /* Uniquify level2 blocks.  */
!   k = 0;
!   for (j = 0; j < t->level2_size; j++)
!     {
!       for (i = 0; i < k; i++)
! 	if (memcmp (&t->level2[i << t->q], &t->level2[j << t->q],
! 		    (1 << t->q) * sizeof (uint32_t)) == 0)
! 	  break;
!       /* Relocate block j to block i.  */
!       reorder2[j] = i;
!       if (i == k)
! 	{
! 	  if (i != j)
! 	    memcpy (&t->level2[i << t->q], &t->level2[j << t->q],
! 		    (1 << t->q) * sizeof (uint32_t));
! 	  k++;
! 	}
!     }
!   t->level2_size = k;
! 
!   for (i = 0; i < t->level1_size; i++)
!     if (t->level1[i] != ~((uint32_t) 0))
!       t->level1[i] = reorder2[t->level1[i]];
! 
!   /* Create and fill the resulting compressed representation.  */
!   t->result_size =
!     5 * sizeof (uint32_t)
!     + t->level1_size * sizeof (uint32_t)
!     + (t->level2_size << t->q) * sizeof (uint32_t)
!     + (t->level3_size << t->p) * sizeof (int32_t);
!   t->result = (char *) xmalloc (t->result_size);
! 
!   level1_offset =
!     5 * sizeof (uint32_t);
!   level2_offset =
!     5 * sizeof (uint32_t)
!     + t->level1_size * sizeof (uint32_t);
!   level3_offset =
!     5 * sizeof (uint32_t)
!     + t->level1_size * sizeof (uint32_t)
!     + (t->level2_size << t->q) * sizeof (uint32_t);
! 
!   ((uint32_t *) t->result)[0] = t->q + t->p;
!   ((uint32_t *) t->result)[1] = t->level1_size;
!   ((uint32_t *) t->result)[2] = t->p;
!   ((uint32_t *) t->result)[3] = (1 << t->q) - 1;
!   ((uint32_t *) t->result)[4] = (1 << t->p) - 1;
! 
!   for (i = 0; i < t->level1_size; i++)
!     ((uint32_t *) (t->result + level1_offset))[i] =
!       (t->level1[i] == ~((uint32_t) 0)
!        ? 0
!        : (t->level1[i] << t->q) * sizeof (uint32_t) + level2_offset);
! 
!   for (i = 0; i < (t->level2_size << t->q); i++)
!     ((uint32_t *) (t->result + level2_offset))[i] =
!       (t->level2[i] == ~((uint32_t) 0)
!        ? 0
!        : (t->level2[i] << t->p) * sizeof (int32_t) + level3_offset);
! 
!   for (i = 0; i < (t->level3_size << t->p); i++)
!     ((int32_t *) (t->result + level3_offset))[i] = t->level3[i];
! 
!   if (t->level1_alloc > 0)
!     free (t->level1);
!   if (t->level2_alloc > 0)
!     free (t->level2);
!   if (t->level3_alloc > 0)
!     free (t->level3);
  }
  
  
--- 3605,3627 ----
      free (t->level3);
  }
  
! #define TABLE wcwidth_table
! #define ELEMENT uint8_t
! #define DEFAULT 0xff
! #include "3level.h"
! 
! #define TABLE wctrans_table
! #define ELEMENT int32_t
! #define DEFAULT 0
! #define wctrans_table_add wctrans_table_add_internal
! #include "3level.h"
! #undef wctrans_table_add
! /* The wctrans_table must actually store the difference between the
!    desired result and the argument.  */
  static inline void
  wctrans_table_add (struct wctrans_table *t, uint32_t wc, uint32_t mapped_wc)
  {
!   wctrans_table_add_internal (t, wc, mapped_wc - wc);
  }
  
  
*** glibc-20000826/locale/programs/ld-collate.c.bak	Mon Aug  7 14:11:10 2000
--- glibc-20000826/locale/programs/ld-collate.c	Sun Aug 27 19:30:30 2000
***************
*** 139,144 ****
--- 139,164 ----
    size_t line;
  };
  
+ /* Sparse table of struct element_t *.  */
+ #define TABLE wchead_table
+ #define ELEMENT struct element_t *
+ #define DEFAULT NULL
+ #define ITERATE
+ #define NO_FINALIZE
+ #include "3level.h"
+ 
+ /* Sparse table of int32_t.  */
+ #define TABLE collidx_table
+ #define ELEMENT int32_t
+ #define DEFAULT 0
+ #include "3level.h"
+ 
+ /* Sparse table of uint32_t.  */
+ #define TABLE collseq_table
+ #define ELEMENT uint32_t
+ #define DEFAULT ~((uint32_t) 0)
+ #include "3level.h"
+ 
  
  /* The real definition of the struct for the LC_COLLATE locale.  */
  struct locale_collate_t
***************
*** 199,208 ****
--- 219,230 ----
    /* Arrays with heads of the list for each of the leading bytes in
       the multibyte sequences.  */
    struct element_t **wcheads;
+   struct wchead_table wcheads_3level;
  
    /* The arrays with the collation sequence order.  */
    unsigned char mbseqorder[256];
    uint32_t *wcseqorder;
+   struct collseq_table wcseqorder_3level;
  };
  
  
***************
*** 211,229 ****
  static uint32_t nrules;
  
  
- /* These are definitions used by some of the functions for handling
-    UTF-8 encoding below.  */
- static const uint32_t encoding_mask[] =
- {
-   ~0x7ff, ~0xffff, ~0x1fffff, ~0x3ffffff
- };
- 
- static const unsigned char encoding_byte[] =
- {
-   0xc0, 0xe0, 0xf0, 0xf8, 0xfc
- };
- 
- 
  /* We need UTF-8 encoding of numbers.  */
  static inline int
  utf8_encode (char *buf, int val)
--- 233,238 ----
***************
*** 240,250 ****
        int step;
  
        for (step = 2; step < 6; ++step)
! 	if ((val & encoding_mask[step - 2]) == 0)
  	  break;
        retval = step;
  
!       *buf = encoding_byte[step - 2];
        --step;
        do
  	{
--- 249,259 ----
        int step;
  
        for (step = 2; step < 6; ++step)
! 	if ((val & (~(uint32_t)0 << (5 * step + 1))) == 0)
  	  break;
        retval = step;
  
!       *buf = (unsigned char) (~0xff >> step);
        --step;
        do
  	{
***************
*** 1634,1742 ****
  	collate->mbheads[i] = &collate->undefined;
        }
  
!   /* Now to the wide character case.  Here we have to find first a good
!      mapping function to get the wide range of wide character values
!      (0x00000000 to 0x7fffffff) to a managable table.  This might take
!      some time so we issue a warning.
! 
!      We use a very trivial hashing function to store the sparse
!      table.  CH % TABSIZE is used as an index.  To solve multiple hits
!      we have N planes.  This guarantees a fixed search time for a
!      character [N / 2].  In the following code we determine the minimum
!      value for TABSIZE * N, where TABSIZE >= 256.
! 
!      Some people complained that this algorithm takes too long.  Well,
!      go on, improve it.  But changing the step size is *not* an
!      option.  Some people changed this to use only sizes of prime
!      numbers.  Think again, do some math.  We are looking for the
!      optimal solution, not something which works in general.  Unless
!      somebody can provide a dynamic programming solution I think this
!      implementation is as good as it can get.  */
!   if (nr_wide_elems > 512 && !be_quiet)
!     fputs (_("\
  Computing table size for collation table might take a while..."),
! 	   stderr);
  
!   min_total = UINT_MAX;
!   act_size = 256;
  
!   /* While we want to have a small total size we are willing to use a
!      little bit larger table if this reduces the number of layers.
!      Therefore we add a little penalty to the number of planes.
!      Maybe this constant has to be adjusted a bit.  */
  #define PENALTY 128
!   do
!     {
!       size_t cnt[act_size];
!       struct element_t *elem[act_size];
!       size_t act_planes = 1;
  
!       memset (cnt, '\0', sizeof cnt);
!       memset (elem, '\0', sizeof elem);
  
!       runp = collate->start;
!       while (runp != NULL)
! 	{
! 	  if (runp->wcs != NULL)
  	    {
! 	      size_t nr = runp->wcs[0] % act_size;
! 	      struct element_t *elemp = elem[nr];
! 
! 	      while (elemp != NULL)
  		{
! 		  if (elemp->wcs[0] == runp->wcs[0])
! 		    break;
! 		  elemp = elemp->wcnext;
! 		}
  
! 	      if (elemp == NULL && ++cnt[nr] > act_planes)
! 		{
! 		  act_planes = cnt[nr];
  
! 		  runp->wcnext = elem[nr];
! 		  elem[nr] = runp;
  
! 		  if ((act_size + PENALTY) * act_planes >= min_total)
! 		    break;
  		}
  	    }
  
! 	  /* Up to the next entry.  */
! 	  runp = runp->next;
! 	}
  
!       if ((act_size + PENALTY) * act_planes < min_total)
! 	{
! 	  min_total = (act_size + PENALTY) * act_planes;
! 	  collate->plane_size = act_size;
! 	  collate->plane_cnt = act_planes;
  	}
  
!       ++act_size;
!     }
!   while (act_size < min_total);
! 
!   if (nr_wide_elems > 512 && !be_quiet)
!     fputs (_(" done\n"), stderr);
  
!   /* Now that we know how large the table has to be we are able to
!      allocate the array and start adding the characters to the lists
!      in the same way we did it for the multibyte characters.  */
!   collate->wcheads = (struct element_t **)
!     obstack_alloc (&collate->mempool, (collate->plane_size
  				       * collate->plane_cnt
  				       * sizeof (struct element_t *)));
-   memset (collate->wcheads, '\0', (collate->plane_size
- 				   * collate->plane_cnt
- 				   * sizeof (struct element_t *)));
  
!   collate->wcseqorder = (uint32_t *)
!     obstack_alloc (&collate->mempool, (collate->plane_size
! 				       * collate->plane_cnt
! 				       * sizeof (uint32_t)));
!   memset (collate->wcseqorder, '\0', (collate->plane_size
! 				      * collate->plane_cnt
! 				      * sizeof (uint32_t)));
  
    /* Start adding.  */
    runp = collate->start;
--- 1643,1768 ----
  	collate->mbheads[i] = &collate->undefined;
        }
  
!   /* Now to the wide character case.  */
!   if (oldstyle_tables)
!     {
!       /*  Here we have to find first a good mapping function to get the
! 	  wide range of wide character values (0x00000000 to 0x7fffffff)
! 	  to a managable table.  This might take some time so we issue
! 	  a warning.
! 
! 	  We use a very trivial hashing function to store the sparse
! 	  table.  CH % TABSIZE is used as an index.  To solve multiple hits
! 	  we have N planes.  This guarantees a fixed search time for a
! 	  character [N / 2].  In the following code we determine the minimum
! 	  value for TABSIZE * N, where TABSIZE >= 256.
! 
! 	  Some people complained that this algorithm takes too long.  Well,
! 	  go on, improve it.  But changing the step size is *not* an
! 	  option.  Some people changed this to use only sizes of prime
! 	  numbers.  Think again, do some math.  We are looking for the
! 	  optimal solution, not something which works in general.  Unless
! 	  somebody can provide a dynamic programming solution I think this
! 	  implementation is as good as it can get.  */
!       if (nr_wide_elems > 512 && !be_quiet)
! 	fputs (_("\
  Computing table size for collation table might take a while..."),
! 	       stderr);
  
!       min_total = UINT_MAX;
!       act_size = 256;
  
!       /* While we want to have a small total size we are willing to use a
! 	 little bit larger table if this reduces the number of layers.
! 	 Therefore we add a little penalty to the number of planes.
! 	 Maybe this constant has to be adjusted a bit.  */
  #define PENALTY 128
!       do
! 	{
! 	  size_t cnt[act_size];
! 	  struct element_t *elem[act_size];
! 	  size_t act_planes = 1;
  
! 	  memset (cnt, '\0', sizeof cnt);
! 	  memset (elem, '\0', sizeof elem);
  
! 	  runp = collate->start;
! 	  while (runp != NULL)
  	    {
! 	      if (runp->wcs != NULL)
  		{
! 		  size_t nr = runp->wcs[0] % act_size;
! 		  struct element_t *elemp = elem[nr];
  
! 		  while (elemp != NULL)
! 		    {
! 		      if (elemp->wcs[0] == runp->wcs[0])
! 			break;
! 		      elemp = elemp->wcnext;
! 		    }
  
! 		  if (elemp == NULL && ++cnt[nr] > act_planes)
! 		    {
! 		      act_planes = cnt[nr];
  
! 		      runp->wcnext = elem[nr];
! 		      elem[nr] = runp;
! 
! 		      if ((act_size + PENALTY) * act_planes >= min_total)
! 			break;
! 		    }
  		}
+ 
+ 	      /* Up to the next entry.  */
+ 	      runp = runp->next;
  	    }
  
! 	  if ((act_size + PENALTY) * act_planes < min_total)
! 	    {
! 	      min_total = (act_size + PENALTY) * act_planes;
! 	      collate->plane_size = act_size;
! 	      collate->plane_cnt = act_planes;
! 	    }
  
! 	  ++act_size;
  	}
+       while (act_size < min_total);
  
!       if (nr_wide_elems > 512 && !be_quiet)
! 	fputs (_(" done\n"), stderr);
  
!       /* Now that we know how large the table has to be we are able to
! 	 allocate the array and start adding the characters to the lists
! 	 in the same way we did it for the multibyte characters.  */
!       collate->wcheads = (struct element_t **)
! 	obstack_alloc (&collate->mempool, (collate->plane_size
! 					   * collate->plane_cnt
! 					   * sizeof (struct element_t *)));
!       memset (collate->wcheads, '\0', (collate->plane_size
  				       * collate->plane_cnt
  				       * sizeof (struct element_t *)));
  
!       collate->wcseqorder = (uint32_t *)
! 	obstack_alloc (&collate->mempool, (collate->plane_size
! 					   * collate->plane_cnt
! 					   * sizeof (uint32_t)));
!       memset (collate->wcseqorder, '\0', (collate->plane_size
! 					  * collate->plane_cnt
! 					  * sizeof (uint32_t)));
!     }
!   else
!     {
!       collate->plane_size = 0;
!       collate->plane_cnt = 0;
! 
!       collate->wcheads_3level.p = 6;
!       collate->wcheads_3level.q = 10;
!       wchead_table_init (&collate->wcheads_3level);
! 
!       collate->wcseqorder_3level.p = 6;
!       collate->wcseqorder_3level.q = 10;
!       collseq_table_init (&collate->wcseqorder_3level);
!     }
  
    /* Start adding.  */
    runp = collate->start;
***************
*** 1744,1769 ****
      {
        if (runp->wcs != NULL)
  	{
  	  struct element_t **eptr;
! 	  struct element_t *lastp = NULL;
  	  size_t idx;
  
! 	  /* Find a free index.  */
! 	  idx = runp->wcs[0] % collate->plane_size;
! 	  while (collate->wcheads[idx] != NULL)
  	    {
! 	      /* Stop if this is an entry with the same starting character.  */
! 	      if (collate->wcheads[idx]->wcs[0] == runp->wcs[0])
! 		break;
  
! 	      idx += collate->plane_size;
  	    }
  
! 	  /* Insert the collation sequence value.  */
! 	  collate->wcseqorder[idx] = runp->wcseqorder;
  
! 	  /* Find the point where to insert in the list.  */
! 	  eptr = &collate->wcheads[idx];
  	  while (*eptr != NULL)
  	    {
  	      if ((*eptr)->nwcs < runp->nwcs)
--- 1770,1811 ----
      {
        if (runp->wcs != NULL)
  	{
+ 	  struct element_t *e;
  	  struct element_t **eptr;
! 	  struct element_t *lastp;
  	  size_t idx;
  
! 	  if (oldstyle_tables)
  	    {
! 	      /* Find a free index.  */
! 	      idx = runp->wcs[0] % collate->plane_size;
! 	      while (collate->wcheads[idx] != NULL)
! 		{
! 		  /* Stop if this is an entry with the same starting character.  */
! 		  if (collate->wcheads[idx]->wcs[0] == runp->wcs[0])
! 		    break;
  
! 		  idx += collate->plane_size;
! 		}
! 
! 	      /* Insert the collation sequence value.  */
! 	      collate->wcseqorder[idx] = runp->wcseqorder;
! 
! 	      /* Find the point where to insert in the list.  */
! 	      eptr = &collate->wcheads[idx];
  	    }
+ 	  else
+ 	    {
+ 	      /* Insert the collation sequence value.  */
+ 	      collseq_table_add (&collate->wcseqorder_3level, runp->wcs[0],
+ 				 runp->wcseqorder);
  
! 	      /* Find the point where to insert in the list.  */
! 	      e = wchead_table_get (&collate->wcheads_3level, runp->wcs[0]);
! 	      eptr = &e;
! 	    }
  
! 	  lastp = NULL;
  	  while (*eptr != NULL)
  	    {
  	      if ((*eptr)->nwcs < runp->nwcs)
***************
*** 1777,1783 ****
  		  if (c == 0)
  		    {
  		      /* This should not happen.  It means that we have
! 			 to symbols with the same byte sequence.  It is
  			 of course an error.  */
  		      error_at_line (0, 0, (*eptr)->file, (*eptr)->line,
  				     _("symbol `%s' has the same encoding as"),
--- 1819,1825 ----
  		  if (c == 0)
  		    {
  		      /* This should not happen.  It means that we have
! 			 two symbols with the same byte sequence.  It is
  			 of course an error.  */
  		      error_at_line (0, 0, (*eptr)->file, (*eptr)->line,
  				     _("symbol `%s' has the same encoding as"),
***************
*** 1802,1807 ****
--- 1844,1851 ----
  	  if (*eptr != NULL)
  	    (*eptr)->wclast = runp;
  	  *eptr = runp;
+ 	  if (!oldstyle_tables && eptr == &e)
+ 	    wchead_table_add (&collate->wcheads_3level, runp->wcs[0], e);
  	dont_insertwc:
  	}
  
***************
*** 1809,1814 ****
--- 1853,1861 ----
        runp = runp->next;
      }
  
+   if (!oldstyle_tables)
+     collseq_table_finalize (&collate->wcseqorder_3level);
+ 
    /* Now determine whether the UNDEFINED entry is needed and if yes,
       whether it was defined.  */
    collate->undefined.used_in_level = need_undefined ? ~0ul : 0;
***************
*** 1967,1975 ****
    struct obstack extrapool;
    struct obstack indirectpool;
    struct section_list *sect;
    uint32_t *names;
    uint32_t *tablewc;
!   size_t table_size;
    uint32_t elem_size;
    uint32_t *elem_table;
    int i;
--- 2014,2023 ----
    struct obstack extrapool;
    struct obstack indirectpool;
    struct section_list *sect;
+   size_t table_size;
    uint32_t *names;
    uint32_t *tablewc;
!   struct collidx_table tablewc_3level;
    uint32_t elem_size;
    uint32_t *elem_table;
    int i;
***************
*** 2320,2334 ****
    assert (idx[cnt] % 4 == 0);
    ++cnt;
  
!   /* Construct a table with the names.  The size of the table is the same
!      as the table with the pointers.  */
!   table_size = collate->plane_size * collate->plane_cnt;
!   names = (uint32_t *) alloca (table_size * sizeof (uint32_t));
!   for (ch = 0; ch < table_size; ++ch)
!     if (collate->wcheads[ch] == NULL)
!       names[ch] = 0;
!     else
!       names[ch] = collate->wcheads[ch]->wcs[0];
  
    assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_NAMES));
    iov[2 + cnt].iov_base = names;
--- 2368,2390 ----
    assert (idx[cnt] % 4 == 0);
    ++cnt;
  
!   if (oldstyle_tables)
!     {
!       /* Construct a table with the names.  The size of the table is the same
! 	 as the table with the pointers.  */
!       table_size = collate->plane_size * collate->plane_cnt;
!       names = (uint32_t *) alloca (table_size * sizeof (uint32_t));
!       for (ch = 0; ch < table_size; ++ch)
! 	if (collate->wcheads[ch] == NULL)
! 	  names[ch] = 0;
! 	else
! 	  names[ch] = collate->wcheads[ch]->wcs[0];
!     }
!   else
!     {
!       table_size = 0;
!       names = NULL;
!     }
  
    assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_NAMES));
    iov[2 + cnt].iov_base = names;
***************
*** 2362,2456 ****
       with the same wide character and add them one after the other to
       the table.  In case we have more than one sequence starting with
       the same byte we have to use extra indirection.  */
!   tablewc = (uint32_t *) alloca (table_size * sizeof (uint32_t));
!   for (ch = 0; ch < table_size; ++ch)
!     if (collate->wcheads[ch] == NULL)
!       {
! 	/* Set the entry to zero.  */
! 	tablewc[ch] = 0;
!       }
!     else if (collate->wcheads[ch]->wcnext == NULL
! 	     && collate->wcheads[ch]->nwcs == 1)
        {
! 	tablewc[ch] = output_weightwc (&weightpool, collate,
! 				       collate->wcheads[ch]);
!       }
!     else
!       {
! 	/* As for the singlebyte table, we recognize sequences and
! 	   compress them.  */
! 	struct element_t *runp = collate->wcheads[ch];
! 	struct element_t *lastp;
! 
! 	tablewc[ch] = -(obstack_object_size (&extrapool) / sizeof (uint32_t));
! 
! 	do
  	  {
! 	    /* Store the current index in the weight table.  We know that
! 	       the current position in the `extrapool' is aligned on a
! 	       32-bit address.  */
! 	    int32_t weightidx;
! 	    int added;
! 
! 	    /* Find out wether this is a single entry or we have more than
! 	       one consecutive entry.  */
! 	    if (runp->wcnext != NULL
! 		&& runp->nwcs == runp->wcnext->nwcs
! 		&& wmemcmp ((wchar_t *) runp->wcs,
! 			    (wchar_t *)runp->wcnext->wcs, runp->nwcs - 1) == 0
! 		&& (runp->wcs[runp->nwcs - 1]
! 		    == runp->wcnext->wcs[runp->nwcs - 1] + 1))
! 	      {
! 		int i;
! 		struct element_t *series_startp = runp;
! 		struct element_t *curp;
  
! 		/* Now add first the initial byte sequence.  */
! 		added = (1 + 1 + 2 * (runp->nwcs - 1)) * sizeof (int32_t);
! 		if (sizeof (int32_t) == sizeof (int))
! 		  obstack_make_room (&extrapool, added);
  
! 		/* More than one consecutive entry.  We mark this by having
! 		   a negative index into the indirect table.  */
! 		if (sizeof (int32_t) == sizeof (int))
! 		  {
! 		    obstack_int_grow_fast (&extrapool,
! 					   -(obstack_object_size (&indirectpool)
! 					     / sizeof (int32_t)));
! 		    obstack_int_grow_fast (&extrapool, runp->nwcs - 1);
! 		  }
! 		else
  		  {
! 		    int32_t i = -(obstack_object_size (&indirectpool)
! 				  / sizeof (int32_t));
! 		    obstack_grow (&extrapool, &i, sizeof (int32_t));
! 		    i = runp->nwcs - 1;
! 		    obstack_grow (&extrapool, &i, sizeof (int32_t));
! 		  }
  
! 		do
! 		  runp = runp->wcnext;
! 		while (runp->wcnext != NULL
! 		       && runp->nwcs == runp->wcnext->nwcs
! 		       && wmemcmp ((wchar_t *) runp->wcs,
! 				   (wchar_t *)runp->wcnext->wcs,
! 				   runp->nwcs - 1) == 0
! 		       && (runp->wcs[runp->nwcs - 1]
! 			   == runp->wcnext->wcs[runp->nwcs - 1] + 1));
  
! 		/* Now walk backward from here to the beginning.  */
! 		curp = runp;
  
! 		for (i = 1; i < runp->nwcs; ++i)
! 		  if (sizeof (int32_t) == sizeof (int))
! 		    obstack_int_grow_fast (&extrapool, curp->wcs[i]);
! 		  else
! 		    obstack_grow (&extrapool, &curp->wcs[i], sizeof (int32_t));
  
! 		/* Now find the end of the consecutive sequence and
!                    add all the indeces in the indirect pool.  */
! 		do
! 		  {
  		    weightidx = output_weightwc (&weightpool, collate, curp);
  		    if (sizeof (int32_t) == sizeof (int))
  		      obstack_int_grow (&indirectpool, weightidx);
--- 2418,2528 ----
       with the same wide character and add them one after the other to
       the table.  In case we have more than one sequence starting with
       the same byte we have to use extra indirection.  */
!   {
!     void add_to_tablewc (uint32_t ch, struct element_t *runp)
        {
! 	if (runp->wcnext == NULL && runp->nwcs == 1)
  	  {
! 	    int32_t weigthidx = output_weightwc (&weightpool, collate, runp);
! 	    if (oldstyle_tables)
! 	      tablewc[ch] = weigthidx;
! 	    else
! 	      collidx_table_add (&tablewc_3level, ch, weigthidx);
! 	  }
! 	else
! 	  {
! 	    /* As for the singlebyte table, we recognize sequences and
! 	       compress them.  */
! 	    struct element_t *lastp;
  
! 	    if (oldstyle_tables)
! 	      tablewc[ch] = -(obstack_object_size (&extrapool) / sizeof (uint32_t));
! 	    else
! 	      collidx_table_add (&tablewc_3level, ch,
! 				 -(obstack_object_size (&extrapool) / sizeof (uint32_t)));
  
! 	    do
! 	      {
! 		/* Store the current index in the weight table.  We know that
! 		   the current position in the `extrapool' is aligned on a
! 		   32-bit address.  */
! 		int32_t weightidx;
! 		int added;
! 
! 		/* Find out wether this is a single entry or we have more than
! 		   one consecutive entry.  */
! 		if (runp->wcnext != NULL
! 		    && runp->nwcs == runp->wcnext->nwcs
! 		    && wmemcmp ((wchar_t *) runp->wcs,
! 				(wchar_t *)runp->wcnext->wcs,
! 				runp->nwcs - 1) == 0
! 		    && (runp->wcs[runp->nwcs - 1]
! 			== runp->wcnext->wcs[runp->nwcs - 1] + 1))
  		  {
! 		    int i;
! 		    struct element_t *series_startp = runp;
! 		    struct element_t *curp;
  
! 		    /* Now add first the initial byte sequence.  */
! 		    added = (1 + 1 + 2 * (runp->nwcs - 1)) * sizeof (int32_t);
! 		    if (sizeof (int32_t) == sizeof (int))
! 		      obstack_make_room (&extrapool, added);
  
! 		    /* More than one consecutive entry.  We mark this by having
! 		       a negative index into the indirect table.  */
! 		    if (sizeof (int32_t) == sizeof (int))
! 		      {
! 			obstack_int_grow_fast (&extrapool,
! 					       -(obstack_object_size (&indirectpool)
! 						 / sizeof (int32_t)));
! 			obstack_int_grow_fast (&extrapool, runp->nwcs - 1);
! 		      }
! 		    else
! 		      {
! 			int32_t i = -(obstack_object_size (&indirectpool)
! 				      / sizeof (int32_t));
! 			obstack_grow (&extrapool, &i, sizeof (int32_t));
! 			i = runp->nwcs - 1;
! 			obstack_grow (&extrapool, &i, sizeof (int32_t));
! 		      }
  
! 		    do
! 		      runp = runp->wcnext;
! 		    while (runp->wcnext != NULL
! 			   && runp->nwcs == runp->wcnext->nwcs
! 			   && wmemcmp ((wchar_t *) runp->wcs,
! 				       (wchar_t *)runp->wcnext->wcs,
! 				       runp->nwcs - 1) == 0
! 			   && (runp->wcs[runp->nwcs - 1]
! 			       == runp->wcnext->wcs[runp->nwcs - 1] + 1));
! 
! 		    /* Now walk backward from here to the beginning.  */
! 		    curp = runp;
! 
! 		    for (i = 1; i < runp->nwcs; ++i)
! 		      if (sizeof (int32_t) == sizeof (int))
! 			obstack_int_grow_fast (&extrapool, curp->wcs[i]);
! 		      else
! 			obstack_grow (&extrapool, &curp->wcs[i],
! 				      sizeof (int32_t));
! 
! 		    /* Now find the end of the consecutive sequence and
! 		       add all the indeces in the indirect pool.  */
! 		    do
! 		      {
! 			weightidx = output_weightwc (&weightpool, collate,
! 						     curp);
! 			if (sizeof (int32_t) == sizeof (int))
! 			  obstack_int_grow (&indirectpool, weightidx);
! 			else
! 			  obstack_grow (&indirectpool, &weightidx,
! 					sizeof (int32_t));
  
! 			curp = curp->wclast;
! 		      }
! 		    while (curp != series_startp);
! 
! 		    /* Add the final weight.  */
  		    weightidx = output_weightwc (&weightpool, collate, curp);
  		    if (sizeof (int32_t) == sizeof (int))
  		      obstack_int_grow (&indirectpool, weightidx);
***************
*** 2458,2525 ****
  		      obstack_grow (&indirectpool, &weightidx,
  				    sizeof (int32_t));
  
! 		    curp = curp->wclast;
  		  }
- 		while (curp != series_startp);
- 
- 		/* Add the final weight.  */
- 		weightidx = output_weightwc (&weightpool, collate, curp);
- 		if (sizeof (int32_t) == sizeof (int))
- 		  obstack_int_grow (&indirectpool, weightidx);
  		else
! 		  obstack_grow (&indirectpool, &weightidx, sizeof (int32_t));
  
! 		/* And add the end byte sequence.  Without length this
!                    time.  */
! 		for (i = 1; i < curp->nwcs; ++i)
! 		  if (sizeof (int32_t) == sizeof (int))
! 		    obstack_int_grow (&extrapool, curp->wcs[i]);
! 		  else
! 		    obstack_grow (&extrapool, &curp->wcs[i], sizeof (int32_t));
  	      }
! 	    else
! 	      {
! 		/* A single entry.  Simply add the index and the length and
! 		   string (except for the first character which is already
! 		   tested for).  */
! 		int i;
  
! 		/* Output the weight info.  */
! 		weightidx = output_weightwc (&weightpool, collate, runp);
  
! 		added = (1 + 1 + runp->nwcs - 1) * sizeof (int32_t);
! 		if (sizeof (int) == sizeof (int32_t))
! 		  obstack_make_room (&extrapool, added);
  
! 		if (sizeof (int32_t) == sizeof (int))
! 		  {
! 		    obstack_int_grow_fast (&extrapool, weightidx);
! 		    obstack_int_grow_fast (&extrapool, runp->nwcs - 1);
! 		  }
! 		else
! 		  {
! 		    int32_t l = runp->nwcs - 1;
! 		    obstack_grow (&extrapool, &weightidx, sizeof (int32_t));
! 		    obstack_grow (&extrapool, &l, sizeof (int32_t));
! 		  }
! 		for (i = 1; i < runp->nwcs; ++i)
! 		  if (sizeof (int32_t) == sizeof (int))
! 		    obstack_int_grow_fast (&extrapool, runp->wcs[i]);
! 		  else
! 		    obstack_grow (&extrapool, &runp->wcs[i], sizeof (int32_t));
! 	      }
  
! 	    /* Next entry.  */
! 	    lastp = runp;
! 	    runp = runp->wcnext;
! 	  }
! 	while (runp != NULL);
        }
  
    /* Now add the four tables.  */
    assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_TABLEWC));
!   iov[2 + cnt].iov_base = tablewc;
!   iov[2 + cnt].iov_len = table_size * sizeof (uint32_t);
    idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
    assert (iov[2 + cnt].iov_len % sizeof (int32_t) == 0);
    assert (idx[cnt] % 4 == 0);
--- 2530,2617 ----
  		      obstack_grow (&indirectpool, &weightidx,
  				    sizeof (int32_t));
  
! 		    /* And add the end byte sequence.  Without length this
! 		       time.  */
! 		    for (i = 1; i < curp->nwcs; ++i)
! 		      if (sizeof (int32_t) == sizeof (int))
! 			obstack_int_grow (&extrapool, curp->wcs[i]);
! 		      else
! 			obstack_grow (&extrapool, &curp->wcs[i],
! 				      sizeof (int32_t));
  		  }
  		else
! 		  {
! 		    /* A single entry.  Simply add the index and the length and
! 		       string (except for the first character which is already
! 		       tested for).  */
! 		    int i;
! 
! 		    /* Output the weight info.  */
! 		    weightidx = output_weightwc (&weightpool, collate, runp);
! 
! 		    added = (1 + 1 + runp->nwcs - 1) * sizeof (int32_t);
! 		    if (sizeof (int) == sizeof (int32_t))
! 		      obstack_make_room (&extrapool, added);
  
! 		    if (sizeof (int32_t) == sizeof (int))
! 		      {
! 			obstack_int_grow_fast (&extrapool, weightidx);
! 			obstack_int_grow_fast (&extrapool, runp->nwcs - 1);
! 		      }
! 		    else
! 		      {
! 			int32_t l = runp->nwcs - 1;
! 			obstack_grow (&extrapool, &weightidx,
! 				      sizeof (int32_t));
! 			obstack_grow (&extrapool, &l, sizeof (int32_t));
! 		      }
! 		    for (i = 1; i < runp->nwcs; ++i)
! 		      if (sizeof (int32_t) == sizeof (int))
! 			obstack_int_grow_fast (&extrapool, runp->wcs[i]);
! 		      else
! 			obstack_grow (&extrapool, &runp->wcs[i],
! 				      sizeof (int32_t));
! 		  }
! 
! 		/* Next entry.  */
! 		lastp = runp;
! 		runp = runp->wcnext;
  	      }
! 	    while (runp != NULL);
! 	  }
!       }
  
!     if (oldstyle_tables)
!       {
! 	tablewc = (uint32_t *) alloca (table_size * sizeof (uint32_t));
  
! 	for (ch = 0; ch < table_size; ++ch)
! 	  if (collate->wcheads[ch] == NULL)
! 	    /* Set the entry to zero.  */
! 	    tablewc[ch] = 0;
! 	  else
! 	    add_to_tablewc (ch, collate->wcheads[ch]);
!       }
!     else
!       {
! 	tablewc_3level.p = 6;
! 	tablewc_3level.q = 10;
! 	collidx_table_init (&tablewc_3level);
  
! 	wchead_table_iterate (&collate->wcheads_3level, add_to_tablewc);
  
! 	collidx_table_finalize (&tablewc_3level);
        }
+   }
  
    /* Now add the four tables.  */
    assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_TABLEWC));
!   iov[2 + cnt].iov_base = (oldstyle_tables
! 			   ? (void *) tablewc
! 			   : (void *) tablewc_3level.result);
!   iov[2 + cnt].iov_len = (oldstyle_tables
! 			  ? table_size * sizeof (uint32_t)
! 			  : tablewc_3level.result_size);
    idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
    assert (iov[2 + cnt].iov_len % sizeof (int32_t) == 0);
    assert (idx[cnt] % 4 == 0);
***************
*** 2671,2678 ****
    ++cnt;
  
    assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_COLLSEQWC));
!   iov[2 + cnt].iov_base = collate->wcseqorder;
!   iov[2 + cnt].iov_len = table_size * sizeof (uint32_t);
    assert (idx[cnt] % 4 == 0);
    ++cnt;
  
--- 2763,2774 ----
    ++cnt;
  
    assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_COLLSEQWC));
!   iov[2 + cnt].iov_base = (oldstyle_tables
! 			   ? (void *) collate->wcseqorder
! 			   : (void *) collate->wcseqorder_3level.result);
!   iov[2 + cnt].iov_len = (oldstyle_tables
! 			  ? table_size * sizeof (uint32_t)
! 			  : collate->wcseqorder_3level.result_size);
    assert (idx[cnt] % 4 == 0);
    ++cnt;
  
*** glibc-20000826/locale/C-collate.c.bak	Mon Jul  3 16:39:30 2000
--- glibc-20000826/locale/C-collate.c	Sun Aug 27 17:25:20 2000
***************
*** 58,63 ****
--- 58,69 ----
  
  static const uint32_t collseqwc[] =
  {
+   8, 1, 8, 0x0, 0xff,
+   /* 1st-level table */
+   6 * sizeof (uint32_t),
+   /* 2nd-level table */
+   7 * sizeof (uint32_t),
+   /* 3rd-level table */
    L'\x00', L'\x01', L'\x02', L'\x03', L'\x04', L'\x05', L'\x06', L'\x07',
    L'\x08', L'\x09', L'\x0a', L'\x0b', L'\x0c', L'\x0d', L'\x0e', L'\x0f',
    L'\x10', L'\x11', L'\x12', L'\x13', L'\x14', L'\x15', L'\x16', L'\x17',
***************
*** 101,123 ****
    NULL,
    18,
    {
      { word: 0 },
      { string: NULL },
      { string: NULL },
      { string: NULL },
      { string: NULL },
      { string: NULL },
      { word: 0 },
      { word: 0 },
      { string: NULL },
      { string: NULL },
      { string: NULL },
      { string: NULL },
      { string: NULL },
      { string: NULL },
      { string: NULL },
      { string: NULL },
      { string: collseqmb },
!     { wstr: collseqwc }
    }
  };
--- 107,147 ----
    NULL,
    18,
    {
+     /* _NL_COLLATE_NRULES */
      { word: 0 },
+     /* _NL_COLLATE_RULESETS */
      { string: NULL },
+     /* _NL_COLLATE_TABLEMB */
      { string: NULL },
+     /* _NL_COLLATE_WEIGHTMB */
      { string: NULL },
+     /* _NL_COLLATE_EXTRAMB */
      { string: NULL },
+     /* _NL_COLLATE_INDIRECTMB */
      { string: NULL },
+     /* _NL_COLLATE_HASH_SIZE */
      { word: 0 },
+     /* _NL_COLLATE_HASH_LAYERS */
      { word: 0 },
+     /* _NL_COLLATE_NAMES */
      { string: NULL },
+     /* _NL_COLLATE_TABLEWC */
      { string: NULL },
+     /* _NL_COLLATE_WEIGHTWC */
      { string: NULL },
+     /* _NL_COLLATE_EXTRAWC */
      { string: NULL },
+     /* _NL_COLLATE_INDIRECTWC */
      { string: NULL },
+     /* _NL_COLLATE_SYMB_HASH_SIZEMB */
      { string: NULL },
+     /* _NL_COLLATE_SYMB_TABLEMB */
      { string: NULL },
+     /* _NL_COLLATE_SYMB_EXTRAMB */
      { string: NULL },
+     /* _NL_COLLATE_COLLSEQMB */
      { string: collseqmb },
!     /* _NL_COLLATE_COLLSEQWC */
!     { string: (const char *) collseqwc }
    }
  };
*** glibc-20000826/locale/Makefile.bak	Tue Aug 15 11:06:58 2000
--- glibc-20000826/locale/Makefile	Sun Aug 27 17:35:00 2000
***************
*** 25,38 ****
  distribute	= localeinfo.h categories.def iso-639.def iso-3166.def \
  		  iso-4217.def weight.h weightwc.h strlen-hash.h elem-hash.h \
  		  indigits.h indigitswc.h outdigits.h outdigitswc.h \
! 		  C-translit.h.in C-translit.h gen-translit.pl \
  		  $(addprefix programs/, \
  			      locale.c localedef.c \
  			      $(localedef-modules:=.c) $(locale-modules:=.c) \
  			      $(lib-modules:=.c) config.h simple-hash.h \
  			      charmap-kw.gperf charmap-kw.h locfile-token.h \
  			      locfile-kw.gperf locfile-kw.h linereader.h \
! 			      locfile.h charmap.h repertoire.h localedef.h)
  routines	= setlocale findlocale loadlocale localeconv nl_langinfo \
  		  mb_cur_max codeset_name \
  		  newlocale duplocale freelocale
--- 25,39 ----
  distribute	= localeinfo.h categories.def iso-639.def iso-3166.def \
  		  iso-4217.def weight.h weightwc.h strlen-hash.h elem-hash.h \
  		  indigits.h indigitswc.h outdigits.h outdigitswc.h \
! 		  coll-lookup.h C-translit.h.in C-translit.h gen-translit.pl \
  		  $(addprefix programs/, \
  			      locale.c localedef.c \
  			      $(localedef-modules:=.c) $(locale-modules:=.c) \
  			      $(lib-modules:=.c) config.h simple-hash.h \
  			      charmap-kw.gperf charmap-kw.h locfile-token.h \
  			      locfile-kw.gperf locfile-kw.h linereader.h \
! 			      locfile.h charmap.h repertoire.h localedef.h \
! 			      3level.h)
  routines	= setlocale findlocale loadlocale localeconv nl_langinfo \
  		  mb_cur_max codeset_name \
  		  newlocale duplocale freelocale

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]