LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-cache.c (source / functions) Hit Total Coverage
Test: output.info Lines: 32 70 45.7 %
Date: 2017-07-14 16:53:18 Functions: 6 14 42.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* cairo - a vector graphics library with display and print output
       2             :  *
       3             :  * Copyright © 2004 Red Hat, Inc.
       4             :  * Copyright © 2005 Red Hat, Inc.
       5             :  *
       6             :  * This library is free software; you can redistribute it and/or
       7             :  * modify it either under the terms of the GNU Lesser General Public
       8             :  * License version 2.1 as published by the Free Software Foundation
       9             :  * (the "LGPL") or, at your option, under the terms of the Mozilla
      10             :  * Public License Version 1.1 (the "MPL"). If you do not alter this
      11             :  * notice, a recipient may use your version of this file under either
      12             :  * the MPL or the LGPL.
      13             :  *
      14             :  * You should have received a copy of the LGPL along with this library
      15             :  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
      16             :  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
      17             :  * You should have received a copy of the MPL along with this library
      18             :  * in the file COPYING-MPL-1.1
      19             :  *
      20             :  * The contents of this file are subject to the Mozilla Public License
      21             :  * Version 1.1 (the "License"); you may not use this file except in
      22             :  * compliance with the License. You may obtain a copy of the License at
      23             :  * http://www.mozilla.org/MPL/
      24             :  *
      25             :  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
      26             :  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
      27             :  * the specific language governing rights and limitations.
      28             :  *
      29             :  * The Original Code is the cairo graphics library.
      30             :  *
      31             :  * The Initial Developer of the Original Code is Red Hat, Inc.
      32             :  *
      33             :  * Contributor(s):
      34             :  *      Keith Packard <keithp@keithp.com>
      35             :  *      Graydon Hoare <graydon@redhat.com>
      36             :  *      Carl Worth <cworth@cworth.org>
      37             :  */
      38             : 
      39             : #include "cairoint.h"
      40             : #include "cairo-error-private.h"
      41             : 
      42             : static void
      43             : _cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
      44             :                                     unsigned long  additional);
      45             : 
      46             : static cairo_bool_t
      47           0 : _cairo_cache_entry_is_non_zero (const void *entry)
      48             : {
      49           0 :     return ((const cairo_cache_entry_t *) entry)->size;
      50             : }
      51             : 
      52             : 
      53             : /**
      54             :  * _cairo_cache_init:
      55             :  * @cache: the #cairo_cache_t to initialise
      56             :  * @keys_equal: a function to return %TRUE if two keys are equal
      57             :  * @entry_destroy: destroy notifier for cache entries
      58             :  * @max_size: the maximum size for this cache
      59             :  * Returns: the newly created #cairo_cache_t
      60             :  *
      61             :  * Creates a new cache using the keys_equal() function to determine
      62             :  * the equality of entries.
      63             :  *
      64             :  * Data is provided to the cache in the form of user-derived version
      65             :  * of #cairo_cache_entry_t. A cache entry must be able to hold hash
      66             :  * code, a size, and the key/value pair being stored in the
      67             :  * cache. Sometimes only the key will be necessary, (as in
      68             :  * _cairo_cache_lookup()), and in these cases the value portion of the
      69             :  * entry need not be initialized.
      70             :  *
      71             :  * The units for max_size can be chosen by the caller, but should be
      72             :  * consistent with the units of the size field of cache entries. When
      73             :  * adding an entry with _cairo_cache_insert() if the total size of
      74             :  * entries in the cache would exceed max_size then entries will be
      75             :  * removed at random until the new entry would fit or the cache is
      76             :  * empty. Then the new entry is inserted.
      77             :  *
      78             :  * There are cases in which the automatic removal of entries is
      79             :  * undesired. If the cache entries have reference counts, then it is a
      80             :  * simple matter to use the reference counts to ensure that entries
      81             :  * continue to live even after being ejected from the cache. However,
      82             :  * in some cases the memory overhead of adding a reference count to
      83             :  * the entry would be objectionable. In such cases, the
      84             :  * _cairo_cache_freeze() and _cairo_cache_thaw() calls can be
      85             :  * used to establish a window during which no automatic removal of
      86             :  * entries will occur.
      87             :  **/
      88             : cairo_status_t
      89           2 : _cairo_cache_init (cairo_cache_t                *cache,
      90             :                    cairo_cache_keys_equal_func_t keys_equal,
      91             :                    cairo_cache_predicate_func_t  predicate,
      92             :                    cairo_destroy_func_t          entry_destroy,
      93             :                    unsigned long                 max_size)
      94             : {
      95           2 :     cache->hash_table = _cairo_hash_table_create (keys_equal);
      96           2 :     if (unlikely (cache->hash_table == NULL))
      97           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
      98             : 
      99           2 :     if (predicate == NULL)
     100           0 :         predicate = _cairo_cache_entry_is_non_zero;
     101           2 :     cache->predicate = predicate;
     102           2 :     cache->entry_destroy = entry_destroy;
     103             : 
     104           2 :     cache->max_size = max_size;
     105           2 :     cache->size = 0;
     106             : 
     107           2 :     cache->freeze_count = 0;
     108             : 
     109           2 :     return CAIRO_STATUS_SUCCESS;
     110             : }
     111             : 
     112             : static void
     113           0 : _cairo_cache_pluck (void *entry, void *closure)
     114             : {
     115           0 :     _cairo_cache_remove (closure, entry);
     116           0 : }
     117             : 
     118             : /**
     119             :  * _cairo_cache_fini:
     120             :  * @cache: a cache to destroy
     121             :  *
     122             :  * Immediately destroys the given cache, freeing all resources
     123             :  * associated with it. As part of this process, the entry_destroy()
     124             :  * function, (as passed to _cairo_cache_init()), will be called for
     125             :  * each entry in the cache.
     126             :  **/
     127             : void
     128           0 : _cairo_cache_fini (cairo_cache_t *cache)
     129             : {
     130           0 :     _cairo_hash_table_foreach (cache->hash_table,
     131             :                                _cairo_cache_pluck,
     132             :                                cache);
     133           0 :     assert (cache->size == 0);
     134           0 :     _cairo_hash_table_destroy (cache->hash_table);
     135           0 : }
     136             : 
     137             : /**
     138             :  * _cairo_cache_freeze:
     139             :  * @cache: a cache with some precious entries in it (or about to be
     140             :  * added)
     141             :  *
     142             :  * Disable the automatic ejection of entries from the cache. For as
     143             :  * long as the cache is "frozen", calls to _cairo_cache_insert() will
     144             :  * add new entries to the cache regardless of how large the cache
     145             :  * grows. See _cairo_cache_thaw().
     146             :  *
     147             :  * Note: Multiple calls to _cairo_cache_freeze() will stack, in that
     148             :  * the cache will remain "frozen" until a corresponding number of
     149             :  * calls are made to _cairo_cache_thaw().
     150             :  **/
     151             : void
     152           7 : _cairo_cache_freeze (cairo_cache_t *cache)
     153             : {
     154           7 :     assert (cache->freeze_count >= 0);
     155             : 
     156           7 :     cache->freeze_count++;
     157           7 : }
     158             : 
     159             : /**
     160             :  * _cairo_cache_thaw:
     161             :  * @cache: a cache, just after the entries in it have become less
     162             :  * precious
     163             :  *
     164             :  * Cancels the effects of _cairo_cache_freeze().
     165             :  *
     166             :  * When a number of calls to _cairo_cache_thaw() is made corresponding
     167             :  * to the number of calls to _cairo_cache_freeze() the cache will no
     168             :  * longer be "frozen". If the cache had grown larger than max_size
     169             :  * while frozen, entries will immediately be ejected (by random) from
     170             :  * the cache until the cache is smaller than max_size. Also, the
     171             :  * automatic ejection of entries on _cairo_cache_insert() will resume.
     172             :  **/
     173             : void
     174           7 : _cairo_cache_thaw (cairo_cache_t *cache)
     175             : {
     176           7 :     assert (cache->freeze_count > 0);
     177             : 
     178           7 :     if (--cache->freeze_count == 0)
     179           7 :         _cairo_cache_shrink_to_accommodate (cache, 0);
     180           7 : }
     181             : 
     182             : /**
     183             :  * _cairo_cache_lookup:
     184             :  * @cache: a cache
     185             :  * @key: the key of interest
     186             :  * @entry_return: pointer for return value
     187             :  *
     188             :  * Performs a lookup in @cache looking for an entry which has a key
     189             :  * that matches @key, (as determined by the keys_equal() function
     190             :  * passed to _cairo_cache_init()).
     191             :  *
     192             :  * Return value: %TRUE if there is an entry in the cache that matches
     193             :  * @key, (which will now be in *entry_return). %FALSE otherwise, (in
     194             :  * which case *entry_return will be %NULL).
     195             :  **/
     196             : void *
     197           0 : _cairo_cache_lookup (cairo_cache_t        *cache,
     198             :                      cairo_cache_entry_t  *key)
     199             : {
     200           0 :     return _cairo_hash_table_lookup (cache->hash_table,
     201             :                                      (cairo_hash_entry_t *) key);
     202             : }
     203             : 
     204             : /**
     205             :  * _cairo_cache_remove_random:
     206             :  * @cache: a cache
     207             :  *
     208             :  * Remove a random entry from the cache.
     209             :  *
     210             :  * Return value: %TRUE if an entry was successfully removed.
     211             :  * %FALSE if there are no entries that can be removed.
     212             :  **/
     213             : static cairo_bool_t
     214           0 : _cairo_cache_remove_random (cairo_cache_t *cache)
     215             : {
     216             :     cairo_cache_entry_t *entry;
     217             : 
     218           0 :     entry = _cairo_hash_table_random_entry (cache->hash_table,
     219             :                                             cache->predicate);
     220           0 :     if (unlikely (entry == NULL))
     221           0 :         return FALSE;
     222             : 
     223           0 :     _cairo_cache_remove (cache, entry);
     224             : 
     225           0 :     return TRUE;
     226             : }
     227             : 
     228             : /**
     229             :  * _cairo_cache_shrink_to_accommodate:
     230             :  * @cache: a cache
     231             :  * @additional: additional size requested in bytes
     232             :  *
     233             :  * If cache is not frozen, eject entries randomly until the size of
     234             :  * the cache is at least @additional bytes less than
     235             :  * cache->max_size. That is, make enough room to accommodate a new
     236             :  * entry of size @additional.
     237             :  **/
     238             : static void
     239           7 : _cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
     240             :                                     unsigned long  additional)
     241             : {
     242          14 :     while (cache->size + additional > cache->max_size) {
     243           0 :         if (! _cairo_cache_remove_random (cache))
     244           0 :             return;
     245             :     }
     246             : }
     247             : 
     248             : /**
     249             :  * _cairo_cache_insert:
     250             :  * @cache: a cache
     251             :  * @entry: an entry to be inserted
     252             :  *
     253             :  * Insert @entry into the cache. If an entry exists in the cache with
     254             :  * a matching key, then the old entry will be removed first, (and the
     255             :  * entry_destroy() callback will be called on it).
     256             :  *
     257             :  * Return value: %CAIRO_STATUS_SUCCESS if successful or
     258             :  * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
     259             :  **/
     260             : cairo_status_t
     261           7 : _cairo_cache_insert (cairo_cache_t       *cache,
     262             :                      cairo_cache_entry_t *entry)
     263             : {
     264             :     cairo_status_t status;
     265             : 
     266           7 :     if (entry->size && ! cache->freeze_count)
     267           0 :         _cairo_cache_shrink_to_accommodate (cache, entry->size);
     268             : 
     269           7 :     status = _cairo_hash_table_insert (cache->hash_table,
     270             :                                        (cairo_hash_entry_t *) entry);
     271           7 :     if (unlikely (status))
     272           0 :         return status;
     273             : 
     274           7 :     cache->size += entry->size;
     275             : 
     276           7 :     return CAIRO_STATUS_SUCCESS;
     277             : }
     278             : 
     279             : /**
     280             :  * _cairo_cache_remove:
     281             :  * @cache: a cache
     282             :  * @entry: an entry that exists in the cache
     283             :  *
     284             :  * Remove an existing entry from the cache.
     285             :  **/
     286             : void
     287           0 : _cairo_cache_remove (cairo_cache_t       *cache,
     288             :                      cairo_cache_entry_t *entry)
     289             : {
     290           0 :     cache->size -= entry->size;
     291             : 
     292           0 :     _cairo_hash_table_remove (cache->hash_table,
     293             :                               (cairo_hash_entry_t *) entry);
     294             : 
     295           0 :     if (cache->entry_destroy)
     296           0 :         cache->entry_destroy (entry);
     297           0 : }
     298             : 
     299             : /**
     300             :  * _cairo_cache_foreach:
     301             :  * @cache: a cache
     302             :  * @cache_callback: function to be called for each entry
     303             :  * @closure: additional argument to be passed to @cache_callback
     304             :  *
     305             :  * Call @cache_callback for each entry in the cache, in a
     306             :  * non-specified order.
     307             :  **/
     308             : void
     309           0 : _cairo_cache_foreach (cairo_cache_t                   *cache,
     310             :                       cairo_cache_callback_func_t      cache_callback,
     311             :                       void                            *closure)
     312             : {
     313           0 :     _cairo_hash_table_foreach (cache->hash_table,
     314             :                                cache_callback,
     315             :                                closure);
     316           0 : }
     317             : 
     318             : unsigned long
     319          14 : _cairo_hash_string (const char *c)
     320             : {
     321             :     /* This is the djb2 hash. */
     322          14 :     unsigned long hash = _CAIRO_HASH_INIT_VALUE;
     323         712 :     while (c && *c)
     324         684 :         hash = ((hash << 5) + hash) + *c++;
     325          14 :     return hash;
     326             : }
     327             : 
     328             : unsigned long
     329           0 : _cairo_hash_bytes (unsigned long hash,
     330             :                    const void *ptr,
     331             :                    unsigned int length)
     332             : {
     333           0 :     const uint8_t *bytes = ptr;
     334             :     /* This is the djb2 hash. */
     335           0 :     while (length--)
     336           0 :         hash = ((hash << 5) + hash) + *bytes++;
     337           0 :     return hash;
     338             : }

Generated by: LCOV version 1.13