(root)/
fontconfig-2.14.2/
src/
fchash.c
       1  /*
       2   * Copyright © 2000 Keith Packard
       3   *
       4   * Permission to use, copy, modify, distribute, and sell this software and its
       5   * documentation for any purpose is hereby granted without fee, provided that
       6   * the above copyright notice appear in all copies and that both that
       7   * copyright notice and this permission notice appear in supporting
       8   * documentation, and that the name of the author(s) not be used in
       9   * advertising or publicity pertaining to distribution of the software without
      10   * specific, written prior permission.  The authors make no
      11   * representations about the suitability of this software for any purpose.  It
      12   * is provided "as is" without express or implied warranty.
      13   *
      14   * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
      15   * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
      16   * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
      17   * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
      18   * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
      19   * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      20   * PERFORMANCE OF THIS SOFTWARE.
      21   */
      22  #include "fcint.h"
      23  
      24  #define FC_HASH_SIZE 227
      25  
      26  typedef struct _FcHashBucket {
      27      struct _FcHashBucket  *next;
      28      void                  *key;
      29      void                  *value;
      30  } FcHashBucket;
      31  
      32  struct _FcHashTable {
      33      FcHashBucket  *buckets[FC_HASH_SIZE];
      34      FcHashFunc     hash_func;
      35      FcCompareFunc  compare_func;
      36      FcCopyFunc     key_copy_func;
      37      FcCopyFunc     value_copy_func;
      38      FcDestroyFunc  key_destroy_func;
      39      FcDestroyFunc  value_destroy_func;
      40  };
      41  
      42  
      43  FcBool
      44  FcHashStrCopy (const void  *src,
      45  	       void       **dest)
      46  {
      47      *dest = FcStrdup (src);
      48  
      49      return *dest != NULL;
      50  }
      51  
      52  FcHashTable *
      53  FcHashTableCreate (FcHashFunc    hash_func,
      54  		   FcCompareFunc compare_func,
      55  		   FcCopyFunc    key_copy_func,
      56  		   FcCopyFunc    value_copy_func,
      57  		   FcDestroyFunc key_destroy_func,
      58  		   FcDestroyFunc value_destroy_func)
      59  {
      60      FcHashTable *ret = malloc (sizeof (FcHashTable));
      61  
      62      if (ret)
      63      {
      64  	memset (ret->buckets, 0, sizeof (FcHashBucket *) * FC_HASH_SIZE);
      65  	ret->hash_func = hash_func;
      66  	ret->compare_func = compare_func;
      67  	ret->key_copy_func = key_copy_func;
      68  	ret->value_copy_func = value_copy_func;
      69  	ret->key_destroy_func = key_destroy_func;
      70  	ret->value_destroy_func = value_destroy_func;
      71      }
      72      return ret;
      73  }
      74  
      75  void
      76  FcHashTableDestroy (FcHashTable *table)
      77  {
      78      int i;
      79  
      80      for (i = 0; i < FC_HASH_SIZE; i++)
      81      {
      82  	FcHashBucket *bucket = table->buckets[i], *prev;
      83  
      84  	while (bucket)
      85  	{
      86  	    if (table->key_destroy_func)
      87  		table->key_destroy_func (bucket->key);
      88  	    if (table->value_destroy_func)
      89  		table->value_destroy_func (bucket->value);
      90  	    prev = bucket;
      91  	    bucket = bucket->next;
      92  	    free (prev);
      93  	}
      94  	table->buckets[i] = NULL;
      95      }
      96      free (table);
      97  }
      98  
      99  FcBool
     100  FcHashTableFind (FcHashTable  *table,
     101  		 const void   *key,
     102  		 void        **value)
     103  {
     104      FcHashBucket *bucket;
     105      FcChar32 hash = table->hash_func (key);
     106  
     107      for (bucket = table->buckets[hash % FC_HASH_SIZE]; bucket; bucket = bucket->next)
     108      {
     109  	if (!table->compare_func(bucket->key, key))
     110  	{
     111  	    if (table->value_copy_func)
     112  	    {
     113  		if (!table->value_copy_func (bucket->value, value))
     114  		    return FcFalse;
     115  	    }
     116  	    else
     117  		*value = bucket->value;
     118  	    return FcTrue;
     119  	}
     120      }
     121      return FcFalse;
     122  }
     123  
     124  static FcBool
     125  FcHashTableAddInternal (FcHashTable *table,
     126  			void        *key,
     127  			void        *value,
     128  			FcBool       replace)
     129  {
     130      FcHashBucket **prev, *bucket, *b;
     131      FcChar32 hash = table->hash_func (key);
     132      FcBool ret = FcFalse;
     133  
     134      bucket = (FcHashBucket *) malloc (sizeof (FcHashBucket));
     135      if (!bucket)
     136  	return FcFalse;
     137      memset (bucket, 0, sizeof (FcHashBucket));
     138      if (table->key_copy_func)
     139  	ret |= !table->key_copy_func (key, &bucket->key);
     140      else
     141  	bucket->key = key;
     142      if (table->value_copy_func)
     143  	ret |= !table->value_copy_func (value, &bucket->value);
     144      else
     145  	bucket->value = value;
     146      if (ret)
     147      {
     148      destroy:
     149  	if (bucket->key && table->key_destroy_func)
     150  	    table->key_destroy_func (bucket->key);
     151  	if (bucket->value && table->value_destroy_func)
     152  	    table->value_destroy_func (bucket->value);
     153  	free (bucket);
     154  
     155  	return !ret;
     156      }
     157    retry:
     158      for (prev = &table->buckets[hash % FC_HASH_SIZE];
     159  	 (b = fc_atomic_ptr_get (prev)); prev = &(b->next))
     160      {
     161  	if (!table->compare_func (b->key, key))
     162  	{
     163  	    if (replace)
     164  	    {
     165  		bucket->next = b->next;
     166  		if (!fc_atomic_ptr_cmpexch (prev, b, bucket))
     167  		    goto retry;
     168  		bucket = b;
     169  	    }
     170  	    else
     171  		ret = FcTrue;
     172  	    goto destroy;
     173  	}
     174      }
     175      bucket->next = NULL;
     176      if (!fc_atomic_ptr_cmpexch (prev, b, bucket))
     177  	goto retry;
     178  
     179      return FcTrue;
     180  }
     181  
     182  FcBool
     183  FcHashTableAdd (FcHashTable *table,
     184  		void        *key,
     185  		void        *value)
     186  {
     187      return FcHashTableAddInternal (table, key, value, FcFalse);
     188  }
     189  
     190  FcBool
     191  FcHashTableReplace (FcHashTable *table,
     192  		    void        *key,
     193  		    void        *value)
     194  {
     195      return FcHashTableAddInternal (table, key, value, FcTrue);
     196  }
     197  
     198  FcBool
     199  FcHashTableRemove (FcHashTable *table,
     200  		   void        *key)
     201  {
     202      FcHashBucket **prev, *bucket;
     203      FcChar32 hash = table->hash_func (key);
     204      FcBool ret = FcFalse;
     205  
     206  retry:
     207      for (prev = &table->buckets[hash % FC_HASH_SIZE];
     208  	 (bucket = fc_atomic_ptr_get (prev)); prev = &(bucket->next))
     209      {
     210  	if (!table->compare_func (bucket->key, key))
     211  	{
     212  	    if (!fc_atomic_ptr_cmpexch (prev, bucket, bucket->next))
     213  		goto retry;
     214  	    if (table->key_destroy_func)
     215  		table->key_destroy_func (bucket->key);
     216  	    if (table->value_destroy_func)
     217  		table->value_destroy_func (bucket->value);
     218  	    free (bucket);
     219  	    ret = FcTrue;
     220  	    break;
     221  	}
     222      }
     223  
     224      return ret;
     225  }