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: 78 91 85.7 %
Date: 2015-08-29 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             : /* Shortcuts */
      39             : 
      40             : #define ZSTR_VAL(zstr)  (zstr)->val
      41             : #define ZSTR_LEN(zstr)  (zstr)->len
      42             : #define ZSTR_H(zstr)    (zstr)->h
      43             : #define ZSTR_HASH(zstr) zend_string_hash_val(zstr)
      44             : 
      45             : /* Compatibility macros */
      46             : 
      47             : #define IS_INTERNED(s)  ZSTR_IS_INTERNED(s)
      48             : #define STR_EMPTY_ALLOC()       ZSTR_EMPTY_ALLOC()
      49             : #define _STR_HEADER_SIZE _ZSTR_HEADER_SIZE
      50             : #define STR_ALLOCA_ALLOC(str, _len, use_heap) ZSTR_ALLOCA_ALLOC(str, _len, use_heap)
      51             : #define STR_ALLOCA_INIT(str, s, len, use_heap) ZSTR_ALLOCA_INIT(str, s, len, use_heap)
      52             : #define STR_ALLOCA_FREE(str, use_heap) ZSTR_ALLOCA_FREE(str, use_heap)
      53             : 
      54             : /*---*/
      55             : 
      56             : #define ZSTR_IS_INTERNED(s)                                     (GC_FLAGS(s) & IS_STR_INTERNED)
      57             : 
      58             : #define ZSTR_EMPTY_ALLOC()                              CG(empty_string)
      59             : 
      60             : #define _ZSTR_HEADER_SIZE XtOffsetOf(zend_string, val)
      61             : 
      62             : #define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1)
      63             : 
      64             : #define ZSTR_ALLOCA_ALLOC(str, _len, use_heap) do { \
      65             :         (str) = (zend_string *)do_alloca(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(_len)), (use_heap)); \
      66             :         GC_REFCOUNT(str) = 1; \
      67             :         GC_TYPE_INFO(str) = IS_STRING; \
      68             :         zend_string_forget_hash_val(str); \
      69             :         ZSTR_LEN(str) = _len; \
      70             : } while (0)
      71             : 
      72             : #define ZSTR_ALLOCA_INIT(str, s, len, use_heap) do { \
      73             :         ZSTR_ALLOCA_ALLOC(str, len, use_heap); \
      74             :         memcpy(ZSTR_VAL(str), (s), (len)); \
      75             :         ZSTR_VAL(str)[(len)] = '\0'; \
      76             : } while (0)
      77             : 
      78             : #define ZSTR_ALLOCA_FREE(str, use_heap) free_alloca(str, use_heap)
      79             : 
      80             : /*---*/
      81             : 
      82             : static zend_always_inline zend_ulong zend_string_hash_val(zend_string *s)
      83             : {
      84   569064103 :         if (!ZSTR_H(s)) {
      85   313172613 :                 ZSTR_H(s) = zend_hash_func(ZSTR_VAL(s), ZSTR_LEN(s));
      86             :         }
      87   569064103 :         return ZSTR_H(s);
      88             : }
      89             : 
      90             : static zend_always_inline void zend_string_forget_hash_val(zend_string *s)
      91             : {
      92   345516653 :         ZSTR_H(s) = 0;
      93             : }
      94             : 
      95             : static zend_always_inline uint32_t zend_string_refcount(const zend_string *s)
      96             : {
      97             :         if (!ZSTR_IS_INTERNED(s)) {
      98             :                 return GC_REFCOUNT(s);
      99             :         }
     100             :         return 1;
     101             : }
     102             : 
     103             : static zend_always_inline uint32_t zend_string_addref(zend_string *s)
     104             : {
     105   143592378 :         if (!ZSTR_IS_INTERNED(s)) {
     106   111065650 :                 return ++GC_REFCOUNT(s);
     107             :         }
     108    32526728 :         return 1;
     109             : }
     110             : 
     111             : static zend_always_inline uint32_t zend_string_delref(zend_string *s)
     112             : {
     113        2866 :         if (!ZSTR_IS_INTERNED(s)) {
     114        2866 :                 return --GC_REFCOUNT(s);
     115             :         }
     116           0 :         return 1;
     117             : }
     118             : 
     119             : static zend_always_inline zend_string *zend_string_alloc(size_t len, int persistent)
     120             : {
     121   678917504 :         zend_string *ret = (zend_string *)pemalloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
     122             : 
     123   336787310 :         GC_REFCOUNT(ret) = 1;
     124             : #if 1
     125             :         /* optimized single assignment */
     126   336787310 :         GC_TYPE_INFO(ret) = IS_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << 8);
     127             : #else
     128             :         GC_TYPE(ret) = IS_STRING;
     129             :         GC_FLAGS(ret) = (persistent ? IS_STR_PERSISTENT : 0);
     130             :         GC_INFO(ret) = 0;
     131             : #endif
     132             :         zend_string_forget_hash_val(ret);
     133   336787310 :         ZSTR_LEN(ret) = len;
     134   336787310 :         return ret;
     135             : }
     136             : 
     137             : static zend_always_inline zend_string *zend_string_safe_alloc(size_t n, size_t m, size_t l, int persistent)
     138             : {
     139      229604 :         zend_string *ret = (zend_string *)safe_pemalloc(n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent);
     140             : 
     141      229604 :         GC_REFCOUNT(ret) = 1;
     142             : #if 1
     143             :         /* optimized single assignment */
     144      229604 :         GC_TYPE_INFO(ret) = IS_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << 8);
     145             : #else
     146             :         GC_TYPE(ret) = IS_STRING;
     147             :         GC_FLAGS(ret) = (persistent ? IS_STR_PERSISTENT : 0);
     148             :         GC_INFO(ret) = 0;
     149             : #endif
     150             :         zend_string_forget_hash_val(ret);
     151      229604 :         ZSTR_LEN(ret) = (n * m) + l;
     152      229604 :         return ret;
     153             : }
     154             : 
     155             : static zend_always_inline zend_string *zend_string_init(const char *str, size_t len, int persistent)
     156             : {
     157   201275726 :         zend_string *ret = zend_string_alloc(len, persistent);
     158             : 
     159   201275726 :         memcpy(ZSTR_VAL(ret), str, len);
     160   201275726 :         ZSTR_VAL(ret)[len] = '\0';
     161   201275726 :         return ret;
     162             : }
     163             : 
     164             : static zend_always_inline zend_string *zend_string_copy(zend_string *s)
     165             : {
     166    11775809 :         if (!ZSTR_IS_INTERNED(s)) {
     167     8708757 :                 GC_REFCOUNT(s)++;
     168             :         }
     169    11775809 :         return s;
     170             : }
     171             : 
     172             : static zend_always_inline zend_string *zend_string_dup(zend_string *s, int persistent)
     173             : {
     174     1033356 :         if (ZSTR_IS_INTERNED(s)) {
     175         187 :                 return s;
     176             :         } else {
     177     2066338 :                 return zend_string_init(ZSTR_VAL(s), ZSTR_LEN(s), persistent);
     178             :         }
     179             : }
     180             : 
     181             : static zend_always_inline zend_string *zend_string_realloc(zend_string *s, size_t len, int persistent)
     182             : {
     183             :         zend_string *ret;
     184             : 
     185     1532887 :         if (!ZSTR_IS_INTERNED(s)) {
     186     1532887 :                 if (EXPECTED(GC_REFCOUNT(s) == 1)) {
     187     3065774 :                         ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
     188     1532887 :                         ZSTR_LEN(ret) = len;
     189             :                         zend_string_forget_hash_val(ret);
     190     1532887 :                         return ret;
     191             :                 } else {
     192           0 :                         GC_REFCOUNT(s)--;
     193             :                 }
     194             :         }
     195           0 :         ret = zend_string_alloc(len, persistent);
     196           0 :         memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN(len, ZSTR_LEN(s)) + 1);
     197           0 :         return ret;
     198             : }
     199             : 
     200             : static zend_always_inline zend_string *zend_string_extend(zend_string *s, size_t len, int persistent)
     201             : {
     202             :         zend_string *ret;
     203             : 
     204             :         ZEND_ASSERT(len >= ZSTR_LEN(s));
     205     6894310 :         if (!ZSTR_IS_INTERNED(s)) {
     206     6893910 :                 if (EXPECTED(GC_REFCOUNT(s) == 1)) {
     207    13723005 :                         ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
     208     6893870 :                         ZSTR_LEN(ret) = len;
     209             :                         zend_string_forget_hash_val(ret);
     210     6893870 :                         return ret;
     211             :                 } else {
     212          40 :                         GC_REFCOUNT(s)--;
     213             :                 }
     214             :         }
     215         440 :         ret = zend_string_alloc(len, persistent);
     216         440 :         memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), ZSTR_LEN(s) + 1);
     217         440 :         return ret;
     218             : }
     219             : 
     220             : static zend_always_inline zend_string *zend_string_truncate(zend_string *s, size_t len, int persistent)
     221             : {
     222             :         zend_string *ret;
     223             : 
     224             :         ZEND_ASSERT(len <= ZSTR_LEN(s));
     225       33336 :         if (!ZSTR_IS_INTERNED(s)) {
     226       33336 :                 if (EXPECTED(GC_REFCOUNT(s) == 1)) {
     227       66672 :                         ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
     228       33336 :                         ZSTR_LEN(ret) = len;
     229             :                         zend_string_forget_hash_val(ret);
     230       33336 :                         return ret;
     231             :                 } else {
     232           0 :                         GC_REFCOUNT(s)--;
     233             :                 }
     234             :         }
     235           0 :         ret = zend_string_alloc(len, persistent);
     236           0 :         memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), len + 1);
     237           0 :         return ret;
     238             : }
     239             : 
     240             : static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s, size_t n, size_t m, size_t l, int persistent)
     241             : {
     242             :         zend_string *ret;
     243             : 
     244           3 :         if (!ZSTR_IS_INTERNED(s)) {
     245           3 :                 if (GC_REFCOUNT(s) == 1) {
     246           3 :                         ret = (zend_string *)safe_perealloc(s, n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent);
     247           3 :                         ZSTR_LEN(ret) = (n * m) + l;
     248             :                         zend_string_forget_hash_val(ret);
     249           3 :                         return ret;
     250             :                 } else {
     251           0 :                         GC_REFCOUNT(s)--;
     252             :                 }
     253             :         }
     254           0 :         ret = zend_string_safe_alloc(n, m, l, persistent);
     255           0 :         memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN((n * m) + l, ZSTR_LEN(s)) + 1);
     256           0 :         return ret;
     257             : }
     258             : 
     259             : static zend_always_inline void zend_string_free(zend_string *s)
     260             : {
     261    62650181 :         if (!ZSTR_IS_INTERNED(s)) {
     262             :                 ZEND_ASSERT(GC_REFCOUNT(s) <= 1);
     263    62306223 :                 pefree(s, GC_FLAGS(s) & IS_STR_PERSISTENT);
     264             :         }
     265             : }
     266             : 
     267             : static zend_always_inline void zend_string_release(zend_string *s)
     268             : {
     269   557695817 :         if (!ZSTR_IS_INTERNED(s)) {
     270   303515230 :                 if (--GC_REFCOUNT(s) == 0) {
     271   186630090 :                         pefree(s, GC_FLAGS(s) & IS_STR_PERSISTENT);
     272             :                 }
     273             :         }
     274             : }
     275             : 
     276             : 
     277             : static zend_always_inline zend_bool zend_string_equals(zend_string *s1, zend_string *s2)
     278             : {
     279        2090 :         return s1 == s2 || (ZSTR_LEN(s1) == ZSTR_LEN(s2) && !memcmp(ZSTR_VAL(s1), ZSTR_VAL(s2), ZSTR_LEN(s1)));
     280             : }
     281             : 
     282             : #define zend_string_equals_ci(s1, s2) \
     283             :         (ZSTR_LEN(s1) == ZSTR_LEN(s2) && !zend_binary_strcasecmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2)))
     284             : 
     285             : #define zend_string_equals_literal_ci(str, c) \
     286             :         (ZSTR_LEN(str) == sizeof(c) - 1 && !zend_binary_strcasecmp(ZSTR_VAL(str), ZSTR_LEN(str), (c), sizeof(c) - 1))
     287             : 
     288             : #define zend_string_equals_literal(str, literal) \
     289             :         (ZSTR_LEN(str) == sizeof(literal)-1 && !memcmp(ZSTR_VAL(str), literal, sizeof(literal) - 1))
     290             : 
     291             : /*
     292             :  * DJBX33A (Daniel J. Bernstein, Times 33 with Addition)
     293             :  *
     294             :  * This is Daniel J. Bernstein's popular `times 33' hash function as
     295             :  * posted by him years ago on comp.lang.c. It basically uses a function
     296             :  * like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best
     297             :  * known hash functions for strings. Because it is both computed very
     298             :  * fast and distributes very well.
     299             :  *
     300             :  * The magic of number 33, i.e. why it works better than many other
     301             :  * constants, prime or not, has never been adequately explained by
     302             :  * anyone. So I try an explanation: if one experimentally tests all
     303             :  * multipliers between 1 and 256 (as RSE did now) one detects that even
     304             :  * numbers are not useable at all. The remaining 128 odd numbers
     305             :  * (except for the number 1) work more or less all equally well. They
     306             :  * all distribute in an acceptable way and this way fill a hash table
     307             :  * with an average percent of approx. 86%.
     308             :  *
     309             :  * If one compares the Chi^2 values of the variants, the number 33 not
     310             :  * even has the best value. But the number 33 and a few other equally
     311             :  * good numbers like 17, 31, 63, 127 and 129 have nevertheless a great
     312             :  * advantage to the remaining numbers in the large set of possible
     313             :  * multipliers: their multiply operation can be replaced by a faster
     314             :  * operation based on just one shift plus either a single addition
     315             :  * or subtraction operation. And because a hash function has to both
     316             :  * distribute good _and_ has to be very fast to compute, those few
     317             :  * numbers should be preferred and seems to be the reason why Daniel J.
     318             :  * Bernstein also preferred it.
     319             :  *
     320             :  *
     321             :  *                  -- Ralf S. Engelschall <rse@engelschall.com>
     322             :  */
     323             : 
     324             : static zend_always_inline zend_ulong zend_inline_hash_func(const char *str, size_t len)
     325             : {
     326   316844563 :         register zend_ulong hash = Z_UL(5381);
     327             : 
     328             :         /* variant with the hash unrolled eight times */
     329   406995573 :         for (; len >= 8; len -= 8) {
     330   406995573 :                 hash = ((hash << 5) + hash) + *str++;
     331   406995573 :                 hash = ((hash << 5) + hash) + *str++;
     332   406995573 :                 hash = ((hash << 5) + hash) + *str++;
     333   406995573 :                 hash = ((hash << 5) + hash) + *str++;
     334   406995573 :                 hash = ((hash << 5) + hash) + *str++;
     335   406995573 :                 hash = ((hash << 5) + hash) + *str++;
     336   406995573 :                 hash = ((hash << 5) + hash) + *str++;
     337   406995573 :                 hash = ((hash << 5) + hash) + *str++;
     338             :         }
     339   316844563 :         switch (len) {
     340    41064728 :                 case 7: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
     341    77852996 :                 case 6: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
     342   123207070 :                 case 5: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
     343   163383552 :                 case 4: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
     344   208871359 :                 case 3: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
     345   245312064 :                 case 2: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
     346   281798907 :                 case 1: hash = ((hash << 5) + hash) + *str++; break;
     347             :                 case 0: break;
     348             : EMPTY_SWITCH_DEFAULT_CASE()
     349             :         }
     350             : 
     351             :         /* Hash value can't be zero, so we always set the high bit */
     352             : #if SIZEOF_ZEND_LONG == 8
     353   316844563 :         return hash | Z_UL(0x8000000000000000);
     354             : #elif SIZEOF_ZEND_LONG == 4
     355             :         return hash | Z_UL(0x80000000);
     356             : #else
     357             : # error "Unknown SIZEOF_ZEND_LONG"
     358             : #endif
     359             : }
     360             : 
     361             : static zend_always_inline void zend_interned_empty_string_init(zend_string **s)
     362             : {
     363             :         zend_string *str;
     364             : 
     365             :         str = zend_string_alloc(sizeof("")-1, 1);
     366             :         ZSTR_VAL(str)[0] = '\000';
     367             : 
     368             : #ifndef ZTS
     369             :         *s = zend_new_interned_string(str);
     370             : #else
     371             :         zend_string_hash_val(str);
     372             :         GC_FLAGS(str) |= IS_STR_INTERNED;
     373             :         *s = str;
     374             : #endif
     375             : }
     376             : 
     377             : static zend_always_inline void zend_interned_empty_string_free(zend_string **s)
     378             : {
     379             :         if (NULL != *s) {
     380             :                 free(*s);
     381             :                 *s = NULL;
     382             :         }
     383             : }
     384             : 
     385             : #endif /* ZEND_STRING_H */
     386             : 
     387             : /*
     388             :  * Local variables:
     389             :  * tab-width: 4
     390             :  * c-basic-offset: 4
     391             :  * indent-tabs-mode: t
     392             :  * End:
     393             :  */

Generated by: LCOV version 1.10

Generated at Sat, 29 Aug 2015 10:22:10 +0000 (29 hours ago)

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