PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - Zend - zend_string.h (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 80 93 86.0 %
Date: 2015-07-31 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2015 Zend Technologies Ltd. (http://www.zend.com) |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 2.00 of the Zend license,     |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.zend.com/license/2_00.txt.                                |
      11             :    | If you did not receive a copy of the Zend license and are unable to  |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@zend.com so we can mail you a copy immediately.              |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Dmitry Stogov <dmitry@zend.com>                             |
      16             :    +----------------------------------------------------------------------+
      17             : */
      18             : 
      19             : /* $Id: $ */
      20             : 
      21             : #ifndef ZEND_STRING_H
      22             : #define ZEND_STRING_H
      23             : 
      24             : #include "zend.h"
      25             : 
      26             : BEGIN_EXTERN_C()
      27             : 
      28             : ZEND_API extern zend_string *(*zend_new_interned_string)(zend_string *str);
      29             : ZEND_API extern void (*zend_interned_strings_snapshot)(void);
      30             : ZEND_API extern void (*zend_interned_strings_restore)(void);
      31             : 
      32             : ZEND_API zend_ulong zend_hash_func(const char *str, size_t len);
      33             : void zend_interned_strings_init(void);
      34             : void zend_interned_strings_dtor(void);
      35             : 
      36             : END_EXTERN_C()
      37             : 
      38             : #define IS_INTERNED(s)                                  (GC_FLAGS(s) & IS_STR_INTERNED)
      39             : 
      40             : #define STR_EMPTY_ALLOC()                               CG(empty_string)
      41             : 
      42             : #define _STR_HEADER_SIZE XtOffsetOf(zend_string, val)
      43             : 
      44             : #define STR_ALLOCA_ALLOC(str, _len, use_heap) do { \
      45             :         (str) = (zend_string *)do_alloca(ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + (_len) + 1), (use_heap)); \
      46             :         GC_REFCOUNT(str) = 1; \
      47             :         GC_TYPE_INFO(str) = IS_STRING; \
      48             :         (str)->h = 0; \
      49             :         (str)->len = (_len); \
      50             : } while (0)
      51             : #define STR_ALLOCA_INIT(str, s, len, use_heap) do { \
      52             :         STR_ALLOCA_ALLOC(str, len, use_heap); \
      53             :         memcpy((str)->val, (s), (len)); \
      54             :         (str)->val[(len)] = '\0'; \
      55             : } while (0)
      56             : 
      57             : #define STR_ALLOCA_FREE(str, use_heap) free_alloca(str, use_heap)
      58             : 
      59             : static zend_always_inline zend_ulong zend_string_hash_val(zend_string *s)
      60             : {
      61   559732590 :         if (!s->h) {
      62   308901804 :                 s->h = zend_hash_func(s->val, s->len);
      63             :         }
      64   559732590 :         return s->h;
      65             : }
      66             : 
      67             : static zend_always_inline void zend_string_forget_hash_val(zend_string *s)
      68             : {
      69     8433430 :         s->h = 0;
      70             : }
      71             : 
      72             : static zend_always_inline uint32_t zend_string_refcount(zend_string *s)
      73             : {
      74             :         if (!IS_INTERNED(s)) {
      75             :                 return GC_REFCOUNT(s);
      76             :         }
      77             :         return 1;
      78             : }
      79             : 
      80             : static zend_always_inline uint32_t zend_string_addref(zend_string *s)
      81             : {
      82   139938356 :         if (!IS_INTERNED(s)) {
      83   109085531 :                 return ++GC_REFCOUNT(s);
      84             :         }
      85    30852825 :         return 1;
      86             : }
      87             : 
      88             : static zend_always_inline uint32_t zend_string_delref(zend_string *s)
      89             : {
      90        2786 :         if (!IS_INTERNED(s)) {
      91        2786 :                 return --GC_REFCOUNT(s);
      92             :         }
      93           0 :         return 1;
      94             : }
      95             : 
      96             : static zend_always_inline zend_string *zend_string_alloc(size_t len, int persistent)
      97             : {
      98   669883456 :         zend_string *ret = (zend_string *)pemalloc(ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + len + 1), persistent);
      99             : 
     100   332301281 :         GC_REFCOUNT(ret) = 1;
     101             : #if 1
     102             :         /* optimized single assignment */
     103   332301281 :         GC_TYPE_INFO(ret) = IS_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << 8);
     104             : #else
     105             :         GC_TYPE(ret) = IS_STRING;
     106             :         GC_FLAGS(ret) = (persistent ? IS_STR_PERSISTENT : 0);
     107             :         GC_INFO(ret) = 0;
     108             : #endif
     109   332301281 :         ret->h = 0;
     110   332301281 :         ret->len = len;
     111   332301281 :         return ret;
     112             : }
     113             : 
     114             : static zend_always_inline zend_string *zend_string_safe_alloc(size_t n, size_t m, size_t l, int persistent)
     115             : {
     116      226337 :         zend_string *ret = (zend_string *)safe_pemalloc(n, m, ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + l + 1), persistent);
     117             : 
     118      226337 :         GC_REFCOUNT(ret) = 1;
     119             : #if 1
     120             :         /* optimized single assignment */
     121      226337 :         GC_TYPE_INFO(ret) = IS_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << 8);
     122             : #else
     123             :         GC_TYPE(ret) = IS_STRING;
     124             :         GC_FLAGS(ret) = (persistent ? IS_STR_PERSISTENT : 0);
     125             :         GC_INFO(ret) = 0;
     126             : #endif
     127      226337 :         ret->h = 0;
     128      226337 :         ret->len = (n * m) + l;
     129      226337 :         return ret;
     130             : }
     131             : 
     132             : static zend_always_inline zend_string *zend_string_init(const char *str, size_t len, int persistent)
     133             : {
     134   198618848 :         zend_string *ret = zend_string_alloc(len, persistent);
     135             : 
     136   198618848 :         memcpy(ret->val, str, len);
     137   198618848 :         ret->val[len] = '\0';
     138   198618848 :         return ret;
     139             : }
     140             : 
     141             : static zend_always_inline zend_string *zend_string_copy(zend_string *s)
     142             : {
     143    11646283 :         if (!IS_INTERNED(s)) {
     144     8613987 :                 GC_REFCOUNT(s)++;
     145             :         }
     146    11646296 :         return s;
     147             : }
     148             : 
     149             : static zend_always_inline zend_string *zend_string_dup(zend_string *s, int persistent)
     150             : {
     151     1002713 :         if (IS_INTERNED(s)) {
     152         184 :                 return s;
     153             :         } else {
     154     2005058 :                 return zend_string_init(s->val, s->len, persistent);
     155             :         }
     156             : }
     157             : 
     158             : static zend_always_inline zend_string *zend_string_realloc(zend_string *s, size_t len, int persistent)
     159             : {
     160             :         zend_string *ret;
     161             : 
     162     1520547 :         if (!IS_INTERNED(s)) {
     163     1520547 :                 if (EXPECTED(GC_REFCOUNT(s) == 1)) {
     164     3041094 :                         ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + len + 1), persistent);
     165     1520547 :                         ret->len = len;
     166             :                         zend_string_forget_hash_val(ret);
     167     1520547 :                         return ret;
     168             :                 } else {
     169           0 :                         GC_REFCOUNT(s)--;
     170             :                 }
     171             :         }
     172           0 :         ret = zend_string_alloc(len, persistent);
     173           0 :         memcpy(ret->val, s->val, (len > s->len ? s->len : len) + 1);
     174           0 :         return ret;
     175             : }
     176             : 
     177             : static zend_always_inline zend_string *zend_string_extend(zend_string *s, size_t len, int persistent)
     178             : {
     179             :         zend_string *ret;
     180             : 
     181             :         ZEND_ASSERT(len >= s->len);
     182     6883921 :         if (!IS_INTERNED(s)) {
     183     6883526 :                 if (EXPECTED(GC_REFCOUNT(s) == 1)) {
     184    13766972 :                         ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + len + 1), persistent);
     185     6883486 :                         ret->len = len;
     186             :                         zend_string_forget_hash_val(ret);
     187     6883486 :                         return ret;
     188             :                 } else {
     189          40 :                         GC_REFCOUNT(s)--;
     190             :                 }
     191             :         }
     192         435 :         ret = zend_string_alloc(len, persistent);
     193         435 :         memcpy(ret->val, s->val, s->len + 1);
     194         435 :         return ret;
     195             : }
     196             : 
     197             : static zend_always_inline zend_string *zend_string_truncate(zend_string *s, size_t len, int persistent)
     198             : {
     199             :         zend_string *ret;
     200             : 
     201             :         ZEND_ASSERT(len <= s->len);
     202       29325 :         if (!IS_INTERNED(s)) {
     203       29325 :                 if (EXPECTED(GC_REFCOUNT(s) == 1)) {
     204       58650 :                         ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + len + 1), persistent);
     205       29325 :                         ret->len = len;
     206             :                         zend_string_forget_hash_val(ret);
     207       29325 :                         return ret;
     208             :                 } else {
     209           0 :                         GC_REFCOUNT(s)--;
     210             :                 }
     211             :         }
     212           0 :         ret = zend_string_alloc(len, persistent);
     213           0 :         memcpy(ret->val, s->val, len + 1);
     214           0 :         return ret;
     215             : }
     216             : 
     217             : static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s, size_t n, size_t m, size_t l, int persistent)
     218             : {
     219             :         zend_string *ret;
     220             : 
     221           3 :         if (!IS_INTERNED(s)) {
     222           3 :                 if (GC_REFCOUNT(s) == 1) {
     223           3 :                         ret = (zend_string *)safe_perealloc(s, n, m, ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + l + 1), persistent);
     224           3 :                         ret->len = (n * m) + l;
     225             :                         zend_string_forget_hash_val(ret);
     226           3 :                         return ret;
     227             :                 } else {
     228           0 :                         GC_REFCOUNT(s)--;
     229             :                 }
     230             :         }
     231           0 :         ret = zend_string_safe_alloc(n, m, l, persistent);
     232           0 :         memcpy(ret->val, s->val, ((n * m) + l > s->len ? s->len : ((n * m) + l)) + 1);
     233           0 :         return ret;
     234             : }
     235             : 
     236             : static zend_always_inline void zend_string_free(zend_string *s)
     237             : {
     238    61975642 :         if (!IS_INTERNED(s)) {
     239             :                 ZEND_ASSERT(GC_REFCOUNT(s) <= 1);
     240    61633490 :                 pefree(s, GC_FLAGS(s) & IS_STR_PERSISTENT);
     241             :         }
     242             : }
     243             : 
     244             : static zend_always_inline void zend_string_release(zend_string *s)
     245             : {
     246   548486866 :         if (!IS_INTERNED(s)) {
     247   298792362 :                 if (--GC_REFCOUNT(s) == 0) {
     248   183943111 :                         pefree(s, GC_FLAGS(s) & IS_STR_PERSISTENT);
     249             :                 }
     250             :         }
     251             : }
     252             : 
     253             : 
     254             : static zend_always_inline zend_bool zend_string_equals(zend_string *s1, zend_string *s2)
     255             : {
     256        2087 :         return s1 == s2 || (s1->len == s2->len && !memcmp(s1->val, s2->val, s1->len));
     257             : }
     258             : 
     259             : #define zend_string_equals_ci(s1, s2) \
     260             :         ((s1)->len == (s2)->len && !zend_binary_strcasecmp((s1)->val, (s1)->len, (s2)->val, (s2)->len))
     261             : 
     262             : #define zend_string_equals_literal_ci(str, c) \
     263             :         ((str)->len == sizeof(c) - 1 && !zend_binary_strcasecmp((str)->val, (str)->len, (c), sizeof(c) - 1))
     264             : 
     265             : #define zend_string_equals_literal(str, literal) \
     266             :         ((str)->len == sizeof(literal)-1 && !memcmp((str)->val, literal, sizeof(literal) - 1))
     267             : 
     268             : /*
     269             :  * DJBX33A (Daniel J. Bernstein, Times 33 with Addition)
     270             :  *
     271             :  * This is Daniel J. Bernstein's popular `times 33' hash function as
     272             :  * posted by him years ago on comp.lang.c. It basically uses a function
     273             :  * like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best
     274             :  * known hash functions for strings. Because it is both computed very
     275             :  * fast and distributes very well.
     276             :  *
     277             :  * The magic of number 33, i.e. why it works better than many other
     278             :  * constants, prime or not, has never been adequately explained by
     279             :  * anyone. So I try an explanation: if one experimentally tests all
     280             :  * multipliers between 1 and 256 (as RSE did now) one detects that even
     281             :  * numbers are not useable at all. The remaining 128 odd numbers
     282             :  * (except for the number 1) work more or less all equally well. They
     283             :  * all distribute in an acceptable way and this way fill a hash table
     284             :  * with an average percent of approx. 86%.
     285             :  *
     286             :  * If one compares the Chi^2 values of the variants, the number 33 not
     287             :  * even has the best value. But the number 33 and a few other equally
     288             :  * good numbers like 17, 31, 63, 127 and 129 have nevertheless a great
     289             :  * advantage to the remaining numbers in the large set of possible
     290             :  * multipliers: their multiply operation can be replaced by a faster
     291             :  * operation based on just one shift plus either a single addition
     292             :  * or subtraction operation. And because a hash function has to both
     293             :  * distribute good _and_ has to be very fast to compute, those few
     294             :  * numbers should be preferred and seems to be the reason why Daniel J.
     295             :  * Bernstein also preferred it.
     296             :  *
     297             :  *
     298             :  *                  -- Ralf S. Engelschall <rse@engelschall.com>
     299             :  */
     300             : 
     301             : static zend_always_inline zend_ulong zend_inline_hash_func(const char *str, size_t len)
     302             : {
     303   312535750 :         register zend_ulong hash = Z_UL(5381);
     304             : 
     305             :         /* variant with the hash unrolled eight times */
     306   401270119 :         for (; len >= 8; len -= 8) {
     307   401270119 :                 hash = ((hash << 5) + hash) + *str++;
     308   401270119 :                 hash = ((hash << 5) + hash) + *str++;
     309   401270119 :                 hash = ((hash << 5) + hash) + *str++;
     310   401270119 :                 hash = ((hash << 5) + hash) + *str++;
     311   401270119 :                 hash = ((hash << 5) + hash) + *str++;
     312   401270119 :                 hash = ((hash << 5) + hash) + *str++;
     313   401270119 :                 hash = ((hash << 5) + hash) + *str++;
     314   401270119 :                 hash = ((hash << 5) + hash) + *str++;
     315             :         }
     316   312535750 :         switch (len) {
     317    40450381 :                 case 7: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
     318    76818190 :                 case 6: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
     319   121530585 :                 case 5: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
     320   161228470 :                 case 4: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
     321   206115615 :                 case 3: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
     322   242052831 :                 case 2: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
     323   278043212 :                 case 1: hash = ((hash << 5) + hash) + *str++; break;
     324             :                 case 0: break;
     325             : EMPTY_SWITCH_DEFAULT_CASE()
     326             :         }
     327             : 
     328             :         /* Hash value can't be zero, so we always set the high bit */
     329             : #if SIZEOF_ZEND_LONG == 8
     330   312535750 :         return hash | Z_UL(0x8000000000000000);
     331             : #elif SIZEOF_ZEND_LONG == 4
     332             :         return hash | Z_UL(0x80000000);
     333             : #else
     334             : # error "Unknown SIZEOF_ZEND_LONG"
     335             : #endif
     336             : }
     337             : 
     338             : static zend_always_inline void zend_interned_empty_string_init(zend_string **s)
     339             : {
     340             :         zend_string *str;
     341             : 
     342             :         str = zend_string_alloc(sizeof("")-1, 1);
     343             :         str->val[0] = '\000';
     344             : 
     345             : #ifndef ZTS
     346             :         *s = zend_new_interned_string(str);
     347             : #else
     348             :         zend_string_hash_val(str);
     349             :         str->gc.u.v.flags |= IS_STR_INTERNED;
     350             :         *s = str;
     351             : #endif
     352             : }
     353             : 
     354             : static zend_always_inline void zend_interned_empty_string_free(zend_string **s)
     355             : {
     356             :         if (NULL != *s) {
     357             :                 free(*s);
     358             :                 *s = NULL;
     359             :         }
     360             : }
     361             : 
     362             : #endif /* ZEND_STRING_H */
     363             : 
     364             : /*
     365             :  * Local variables:
     366             :  * tab-width: 4
     367             :  * c-basic-offset: 4
     368             :  * indent-tabs-mode: t
     369             :  * End:
     370             :  */

Generated by: LCOV version 1.10

Generated at Fri, 31 Jul 2015 08:58:44 +0000 (2 days ago)

Copyright © 2005-2015 The PHP Group
All rights reserved.