(root)/
glibc-2.38/
locale/
programs/
3level.h
       1  /* Copyright (C) 2000-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3     Contributed by Bruno Haible <haible@clisp.cons.org>, 2000.
       4  
       5     This program is free software; you can redistribute it and/or modify
       6     it under the terms of the GNU General Public License as published
       7     by the Free Software Foundation; version 2 of the License, or
       8     (at your option) any later version.
       9  
      10     This program is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13     GNU General Public License for more details.
      14  
      15     You should have received a copy of the GNU General Public License
      16     along with this program; if not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <stdint.h>
      19  
      20  /* Construction of sparse 3-level tables.
      21     See wchar-lookup.h or coll-lookup.h for their structure and the
      22     meaning of p and q.
      23  
      24     Before including this file, set
      25       TABLE        to the name of the structure to be defined
      26       ELEMENT      to the type of every entry
      27       DEFAULT      to the default value for empty entries
      28       ITERATE      if you want the TABLE_iterate function to be defined
      29       NO_ADD_LOCALE  if you don't want the add_locale_TABLE function
      30  		    to be defined
      31  
      32     This will define
      33  
      34       struct TABLE;
      35       void TABLE_init (struct TABLE *t);
      36       ELEMENT TABLE_get (struct TABLE *t, uint32_t wc);
      37       void TABLE_add (struct TABLE *t, uint32_t wc, ELEMENT value);
      38       void TABLE_iterate (struct TABLE *t,
      39  			 void (*fn) (uint32_t wc, ELEMENT value));
      40       void add_locale_TABLE (struct locale_file *file, struct TABLE *t);
      41  */
      42  
      43  #define CONCAT(a,b) CONCAT1(a,b)
      44  #define CONCAT1(a,b) a##b
      45  
      46  struct TABLE
      47  {
      48    /* Parameters.  */
      49    unsigned int p;
      50    unsigned int q;
      51    /* Working representation.  */
      52    size_t level1_alloc;
      53    size_t level1_size;
      54    uint32_t *level1;
      55    size_t level2_alloc;
      56    size_t level2_size;
      57    uint32_t *level2;
      58    size_t level3_alloc;
      59    size_t level3_size;
      60    ELEMENT *level3;
      61    /* Size of compressed representation.  */
      62    size_t result_size;
      63  };
      64  
      65  /* Initialize.  Assumes t->p and t->q have already been set.  */
      66  static inline void
      67  CONCAT(TABLE,_init) (struct TABLE *t)
      68  {
      69    t->level1 = NULL;
      70    t->level1_alloc = t->level1_size = 0;
      71    t->level2 = NULL;
      72    t->level2_alloc = t->level2_size = 0;
      73    t->level3 = NULL;
      74    t->level3_alloc = t->level3_size = 0;
      75  }
      76  
      77  /* Marker for an empty slot.  This has the value 0xFFFFFFFF, regardless
      78     whether 'int' is 16 bit, 32 bit, or 64 bit.  */
      79  #define EMPTY ((uint32_t) ~0)
      80  
      81  /* Retrieve an entry.  */
      82  static inline ELEMENT
      83  __attribute ((always_inline))
      84  CONCAT(TABLE,_get) (struct TABLE *t, uint32_t wc)
      85  {
      86    uint32_t index1 = wc >> (t->q + t->p);
      87    if (index1 < t->level1_size)
      88      {
      89        uint32_t lookup1 = t->level1[index1];
      90        if (lookup1 != EMPTY)
      91  	{
      92  	  uint32_t index2 = ((wc >> t->p) & ((1 << t->q) - 1))
      93  			    + (lookup1 << t->q);
      94  	  uint32_t lookup2 = t->level2[index2];
      95  	  if (lookup2 != EMPTY)
      96  	    {
      97  	      uint32_t index3 = (wc & ((1 << t->p) - 1))
      98  				+ (lookup2 << t->p);
      99  	      ELEMENT lookup3 = t->level3[index3];
     100  
     101  	      return lookup3;
     102  	    }
     103  	}
     104      }
     105    return DEFAULT;
     106  }
     107  
     108  /* Add one entry.  */
     109  static void
     110  CONCAT(TABLE,_add) (struct TABLE *t, uint32_t wc, ELEMENT value)
     111  {
     112    uint32_t index1 = wc >> (t->q + t->p);
     113    uint32_t index2 = (wc >> t->p) & ((1 << t->q) - 1);
     114    uint32_t index3 = wc & ((1 << t->p) - 1);
     115    size_t i, i1, i2;
     116  
     117    if (value == CONCAT(TABLE,_get) (t, wc))
     118      return;
     119  
     120    if (index1 >= t->level1_size)
     121      {
     122        if (index1 >= t->level1_alloc)
     123  	{
     124  	  size_t alloc = 2 * t->level1_alloc;
     125  	  if (alloc <= index1)
     126  	    alloc = index1 + 1;
     127  	  t->level1 = (uint32_t *) xrealloc ((char *) t->level1,
     128  					     alloc * sizeof (uint32_t));
     129  	  t->level1_alloc = alloc;
     130  	}
     131        while (index1 >= t->level1_size)
     132  	t->level1[t->level1_size++] = EMPTY;
     133      }
     134  
     135    if (t->level1[index1] == EMPTY)
     136      {
     137        if (t->level2_size == t->level2_alloc)
     138  	{
     139  	  size_t alloc = 2 * t->level2_alloc + 1;
     140  	  t->level2 = (uint32_t *) xrealloc ((char *) t->level2,
     141  					     (alloc << t->q) * sizeof (uint32_t));
     142  	  t->level2_alloc = alloc;
     143  	}
     144        i1 = t->level2_size << t->q;
     145        i2 = (t->level2_size + 1) << t->q;
     146        for (i = i1; i < i2; i++)
     147  	t->level2[i] = EMPTY;
     148        t->level1[index1] = t->level2_size++;
     149      }
     150  
     151    index2 += t->level1[index1] << t->q;
     152  
     153    if (t->level2[index2] == EMPTY)
     154      {
     155        if (t->level3_size == t->level3_alloc)
     156  	{
     157  	  size_t alloc = 2 * t->level3_alloc + 1;
     158  	  t->level3 = (ELEMENT *) xrealloc ((char *) t->level3,
     159  					    (alloc << t->p) * sizeof (ELEMENT));
     160  	  t->level3_alloc = alloc;
     161  	}
     162        i1 = t->level3_size << t->p;
     163        i2 = (t->level3_size + 1) << t->p;
     164        for (i = i1; i < i2; i++)
     165  	t->level3[i] = DEFAULT;
     166        t->level2[index2] = t->level3_size++;
     167      }
     168  
     169    index3 += t->level2[index2] << t->p;
     170  
     171    t->level3[index3] = value;
     172  }
     173  
     174  #ifdef ITERATE
     175  /* Apply a function to all entries in the table.  */
     176  static void
     177  CONCAT(TABLE,_iterate) (struct TABLE *t,
     178  			void (*fn) (uint32_t wc, ELEMENT value))
     179  {
     180    uint32_t index1;
     181    for (index1 = 0; index1 < t->level1_size; index1++)
     182      {
     183        uint32_t lookup1 = t->level1[index1];
     184        if (lookup1 != EMPTY)
     185  	{
     186  	  uint32_t lookup1_shifted = lookup1 << t->q;
     187  	  uint32_t index2;
     188  	  for (index2 = 0; index2 < (1 << t->q); index2++)
     189  	    {
     190  	      uint32_t lookup2 = t->level2[index2 + lookup1_shifted];
     191  	      if (lookup2 != EMPTY)
     192  		{
     193  		  uint32_t lookup2_shifted = lookup2 << t->p;
     194  		  uint32_t index3;
     195  		  for (index3 = 0; index3 < (1 << t->p); index3++)
     196  		    {
     197  		      ELEMENT lookup3 = t->level3[index3 + lookup2_shifted];
     198  		      if (lookup3 != DEFAULT)
     199  			fn ((((index1 << t->q) + index2) << t->p) + index3,
     200  			    lookup3);
     201  		    }
     202  		}
     203  	    }
     204  	}
     205      }
     206  }
     207  #endif
     208  
     209  #ifndef NO_ADD_LOCALE
     210  /* Finalize and shrink.  */
     211  static void
     212  CONCAT(add_locale_,TABLE) (struct locale_file *file, struct TABLE *t)
     213  {
     214    size_t i, j, k;
     215    uint32_t reorder3[t->level3_size];
     216    uint32_t reorder2[t->level2_size];
     217    uint32_t level2_offset, level3_offset, last_offset;
     218  
     219    /* Uniquify level3 blocks.  */
     220    k = 0;
     221    for (j = 0; j < t->level3_size; j++)
     222      {
     223        for (i = 0; i < k; i++)
     224  	if (memcmp (&t->level3[i << t->p], &t->level3[j << t->p],
     225  		    (1 << t->p) * sizeof (ELEMENT)) == 0)
     226  	  break;
     227        /* Relocate block j to block i.  */
     228        reorder3[j] = i;
     229        if (i == k)
     230  	{
     231  	  if (i != j)
     232  	    memcpy (&t->level3[i << t->p], &t->level3[j << t->p],
     233  		    (1 << t->p) * sizeof (ELEMENT));
     234  	  k++;
     235  	}
     236      }
     237    t->level3_size = k;
     238  
     239    for (i = 0; i < (t->level2_size << t->q); i++)
     240      if (t->level2[i] != EMPTY)
     241        t->level2[i] = reorder3[t->level2[i]];
     242  
     243    /* Uniquify level2 blocks.  */
     244    k = 0;
     245    for (j = 0; j < t->level2_size; j++)
     246      {
     247        for (i = 0; i < k; i++)
     248  	if (memcmp (&t->level2[i << t->q], &t->level2[j << t->q],
     249  		    (1 << t->q) * sizeof (uint32_t)) == 0)
     250  	  break;
     251        /* Relocate block j to block i.  */
     252        reorder2[j] = i;
     253        if (i == k)
     254  	{
     255  	  if (i != j)
     256  	    memcpy (&t->level2[i << t->q], &t->level2[j << t->q],
     257  		    (1 << t->q) * sizeof (uint32_t));
     258  	  k++;
     259  	}
     260      }
     261    t->level2_size = k;
     262  
     263    for (i = 0; i < t->level1_size; i++)
     264      if (t->level1[i] != EMPTY)
     265        t->level1[i] = reorder2[t->level1[i]];
     266  
     267    /* Create and fill the resulting compressed representation.  */
     268    last_offset =
     269      5 * sizeof (uint32_t)
     270      + t->level1_size * sizeof (uint32_t)
     271      + (t->level2_size << t->q) * sizeof (uint32_t)
     272      + (t->level3_size << t->p) * sizeof (ELEMENT);
     273    t->result_size = LOCFILE_ALIGN_UP (last_offset);
     274  
     275    level2_offset =
     276      5 * sizeof (uint32_t)
     277      + t->level1_size * sizeof (uint32_t);
     278    level3_offset =
     279      5 * sizeof (uint32_t)
     280      + t->level1_size * sizeof (uint32_t)
     281      + (t->level2_size << t->q) * sizeof (uint32_t);
     282  
     283    start_locale_structure (file);
     284    add_locale_uint32 (file, t->q + t->p);
     285    add_locale_uint32 (file, t->level1_size);
     286    add_locale_uint32 (file, t->p);
     287    add_locale_uint32 (file, (1 << t->q) - 1);
     288    add_locale_uint32 (file, (1 << t->p) - 1);
     289  
     290    for (i = 0; i < t->level1_size; i++)
     291      add_locale_uint32
     292        (file,
     293         t->level1[i] == EMPTY
     294         ? 0
     295         : (t->level1[i] << t->q) * sizeof (uint32_t) + level2_offset);
     296  
     297    for (i = 0; i < (t->level2_size << t->q); i++)
     298      add_locale_uint32
     299        (file,
     300         t->level2[i] == EMPTY
     301         ? 0
     302         : (t->level2[i] << t->p) * sizeof (ELEMENT) + level3_offset);
     303  
     304    if (sizeof (ELEMENT) == 1)
     305      add_locale_raw_data (file, t->level3, t->level3_size << t->p);
     306    else if (sizeof (ELEMENT) == sizeof (uint32_t))
     307      add_locale_uint32_array (file, (uint32_t *) t->level3,
     308  			     t->level3_size << t->p);
     309    else
     310      abort ();
     311    align_locale_data (file, LOCFILE_ALIGN);
     312    end_locale_structure (file);
     313  
     314    if (t->level1_alloc > 0)
     315      free (t->level1);
     316    if (t->level2_alloc > 0)
     317      free (t->level2);
     318    if (t->level3_alloc > 0)
     319      free (t->level3);
     320  }
     321  #endif
     322  
     323  #undef EMPTY
     324  #undef TABLE
     325  #undef ELEMENT
     326  #undef DEFAULT
     327  #undef ITERATE
     328  #undef NO_ADD_LOCALE