pike.git / src / stralloc.c

version» Context lines:

pike.git/src/stralloc.c:45:   static unsigned int need_more_hash_prefix_depth=0;      static unsigned int need_new_hashkey_depth=0;   static size_t hashkey = 0;      static unsigned INT32 htable_size=0;   static struct pike_string **base_table=0;   static unsigned INT32 num_strings=0;   PMOD_EXPORT struct pike_string *empty_pike_string = 0;    + struct substring_pike_string { +  struct pike_string str; +  struct pike_string *parent; + }; +    /*** Main string hash function ***/      #define StrHash(s,len) low_do_hash(s,len,0)   #define low_do_hash(STR,LEN,SHIFT) low_hashmem( (STR), (LEN)<<(SHIFT), hash_prefix_len<<(SHIFT), hashkey )   #define do_hash(STR) low_do_hash(STR->str,STR->len,STR->size_shift)      static INLINE int string_is_block_allocated(const struct pike_string * s) {    return (s->alloc_type == STRING_ALLOC_BA);   }   
pike.git/src/stralloc.c:67:   }      static INLINE int string_is_static(const struct pike_string * s) {    return s->alloc_type == STRING_ALLOC_STATIC;   }      static INLINE int string_is_substring(const struct pike_string * s) {    return s->alloc_type == STRING_ALLOC_SUBSTRING;   }    - static INLINE int string_may_modify(const struct pike_string * s) { -  return !string_is_static(s) && !string_is_substring(s) && s->refs == 1; + static struct pike_string *substring_content_string(const struct pike_string *s) + { +  return ((struct substring_pike_string*)s)->parent;   }    -  + static INLINE int string_may_modify(const struct pike_string * s) + { +  return !string_is_static(s) && !string_is_substring(s) +  && s->refs == 1; + }    -  + static INLINE int string_may_modify_len(const struct pike_string * s) + { +  return s->refs == 1; + } +  +    /* Returns true if str could contain n. */   PMOD_EXPORT int string_range_contains( struct pike_string *str, int n )   {    INT32 min, max;    check_string_range( str, 1, &min, &max );    if( n >= min && n <= max )    return 1;    return 0;   }   
pike.git/src/stralloc.c:244:    if((unsigned INT32)*s++>=65536)    return 2;    }while(s<e);    return 1;    }    s++;    }    return 0;   }    - static INLINE unsigned min_magnitude(const unsigned c) + static INLINE enum size_shift min_magnitude(const unsigned c)   {    return LIKELY(c<256) ? 0 : LIKELY(c<65536) ? 1 : 2;   }      void low_set_index(struct pike_string *s, ptrdiff_t pos, int value)   {   #ifdef PIKE_DEBUG    if(pos > s->len || pos<0) {    if (s->len) {    Pike_fatal("String index %"PRINTPTRDIFFT"d is out of "
pike.git/src/stralloc.c:277:       if(!s->size_shift)    STR0(s)[pos]=value;    else if(s->size_shift == 1)    STR1(s)[pos]=value;    else    STR2(s)[pos]=value;   }      #ifdef PIKE_DEBUG - PMOD_EXPORT struct pike_string *debug_check_size_shift(const struct pike_string *a, int shift) + PMOD_EXPORT struct pike_string *debug_check_size_shift(const struct pike_string *a, enum size_shift shift)   {    if(a->size_shift != shift)    Pike_fatal("Wrong STRX macro used!\n");    return (struct pike_string*)a;   }   #endif      #define CONVERT(FROM,TO) \    void PIKE_CONCAT4(convert_,FROM,_to_,TO) (PIKE_CONCAT(p_wchar,TO) *to, \    const PIKE_CONCAT(p_wchar,FROM) *from, \
pike.git/src/stralloc.c:452:   }   #else   #define locate_problem(X)   #endif /* PIKE_DEBUG */      /* Find a string in the shared string table.    * This assumes that the string is minimized!!!!    */   static struct pike_string *internal_findstring(const char *s,    ptrdiff_t len, -  int size_shift, +  enum size_shift size_shift,    size_t hval)   {    struct pike_string *curr;   //,**prev, **base;    unsigned int depth=0;    unsigned int prefix_depth=0;       size_t h;    h=HMODULO(hval);    for(curr = base_table[h]; curr; curr = curr->next)
pike.git/src/stralloc.c:479: Inside #if defined(PIKE_DEBUG)
   Pike_fatal("String with no references.\n");    }   #endif    debug_malloc_touch(curr);       if ( len == curr->len &&    size_shift == curr->size_shift &&    hval == curr->hval &&    ( curr->str == s ||    !memcmp(curr->str, s,len<<size_shift))) /* found it */ -  { -  /* *prev = curr->next; */ -  /* curr->next = *base; */ -  /* *base = curr; */ -  return curr; /* pointer to string */ -  } +  return curr; +     depth++;    if (curr->len > (ptrdiff_t)hash_prefix_len)    prefix_depth++;    }    if (depth > need_new_hashkey_depth) {    /* Keep track of whether the hashtable is getting unbalanced. */    need_new_hashkey_depth = depth;    }    /* These heuruistics might require tuning! /Hubbe */    if (prefix_depth > need_more_hash_prefix_depth)
pike.git/src/stralloc.c:608:       if(old_base)    free(old_base);   }      /* Allocation of strings */      #define STRING_BLOCK 2048       - struct substring_pike_string { -  struct pike_string str; -  struct pike_string *parent; - }; + static struct block_allocator string_allocator = +  BA_INIT(sizeof(struct pike_string), STRING_BLOCK); + static struct block_allocator substring_allocator = +  BA_INIT(sizeof(struct substring_pike_string), STRING_BLOCK>>2);    - static struct block_allocator string_allocator = BA_INIT(sizeof(struct pike_string), STRING_BLOCK); - static struct block_allocator substring_allocator = BA_INIT(sizeof(struct substring_pike_string), STRING_BLOCK>>2); -  - static void free_unlinked_pike_string(struct pike_string * s) + static void free_string_content(struct pike_string * s)   {    switch (s->alloc_type)    { -  +  case STRING_ALLOC_STATIC: +  break;    case STRING_ALLOC_MALLOC:    free(s->str);    break;    case STRING_ALLOC_BA:    ba_free(&string_allocator, s->str);    break;    case STRING_ALLOC_SUBSTRING: -  if( ((struct substring_pike_string*)s)->parent ) +     free_string(((struct substring_pike_string*)s)->parent); -  ba_free(&substring_allocator, s); -  return; +  break;    } -  + }    -  + static void free_unlinked_pike_string(struct pike_string * s) + { +  free_string_content(s); +  switch(s->struct_type) +  { +  case STRING_STRUCT_STRING:    ba_free(&string_allocator, s); -  +  break; +  case STRING_STRUCT_SUBSTRING: +  ba_free(&substring_allocator, s); +  break;    } -  + }    -  +    /* note that begin_shared_string expects the _exact_ size of the string,    * not the maximum size    */   PMOD_EXPORT struct pike_string *debug_begin_shared_string(size_t len)   {    return debug_begin_wide_shared_string(len, 0);   }      static void link_pike_string(struct pike_string *s, size_t hval)   {    size_t h; -  +    #ifdef PIKE_DEBUG    if (!(s->flags & STRING_NOT_SHARED)) {    debug_dump_pike_string(s, 70);    Pike_fatal("String already linked.\n");    }       if (PIKE_MEM_NOT_DEF_RANGE (s->str, (s->len + 1) << s->size_shift))    Pike_fatal ("Got undefined contents in pike string %p.\n", s);   #endif   
pike.git/src/stralloc.c:727:    tmp2->hval=do_hash(tmp2); /* compute new hash value */    h2=HMODULO(tmp2->hval);       tmp2->next=base_table[h2]; /* and re-hash */    base_table[h2]=tmp2;    }    }    }   }    - PMOD_EXPORT struct pike_string *debug_begin_wide_shared_string(size_t len, int shift) + PMOD_EXPORT struct pike_string *debug_begin_wide_shared_string(size_t len, enum size_shift shift)   {    struct pike_string *t = NULL;    size_t bytes = (len+1) << shift;    ONERROR fe;   #ifdef PIKE_DEBUG    if(d_flag>10)    verify_shared_strings_tables();   #endif   #ifdef PIKE_DEBUG    if (shift > 2)    Pike_fatal("Unsupported string shift: %d\n", shift);   #endif /* PIKE_DEBUG */ -  t=(struct pike_string *)ba_alloc(&string_allocator); +  t=ba_alloc(&string_allocator);    /* we mark the string as static here, to avoid double free if the    * allocations fail    */    t->flags = STRING_NOT_HASHED|STRING_NOT_SHARED;    t->alloc_type = STRING_ALLOC_STATIC; -  +  t->struct_type = STRING_STRUCT_STRING;    SET_ONERROR(fe,free_unlinked_pike_string,t);    if (bytes <= sizeof(struct pike_string))    {    t->str = ba_alloc(&string_allocator);    t->alloc_type = STRING_ALLOC_BA;    } else {    t->str = xalloc(bytes);    t->alloc_type = STRING_ALLOC_MALLOC;    }    t->refs = 0;
pike.git/src/stralloc.c:771:    low_set_index(t,len,0);    return t;   }      static struct pike_string * make_static_string(const char * str, size_t len,    enum size_shift shift)   {    struct pike_string * t = ba_alloc(&string_allocator);       t->flags = STRING_NOT_HASHED|STRING_NOT_SHARED; +  t->size_shift = shift;    t->alloc_type = STRING_ALLOC_STATIC; -  +  t->struct_type = STRING_STRUCT_STRING;    t->str = (char *)str;    t->refs = 0;    t->len = len; -  t->size_shift = shift; -  add_ref(t); /* For DMALLOC */ +  add_ref(t); /* For DMALLOC */       return t;   }      PMOD_EXPORT struct pike_string * make_shared_static_string(const char *str, size_t len,    enum size_shift shift)   {    struct pike_string *s;    ptrdiff_t h = StrHash(str, len);       s = internal_findstring(str,len,shift,h);       if (!s) {    s = make_static_string(str, len, shift);    link_pike_string(s, h);    } else { -  if (!string_is_static(s)) { -  if (string_is_block_allocated(s)) { -  ba_free(&string_allocator, s->str); -  } else if(string_is_substring(s)) { -  if( ((struct substring_pike_string *)s)->parent ) { -  free_string( ((struct substring_pike_string *)s)->parent ); -  ((struct substring_pike_string *)s)->parent = NULL; -  } -  s->str = (char*)str; -  /* NOTE: We MUST NOT change the alloc_type, since that -  * would associate s with the wrong block allocator, -  * and cause a crash when s is eventually freed. -  */ -  goto done; -  } -  else +  if (!string_is_static(s))    { -  free(s->str); -  } +  free_string_content(s);    s->alloc_type = STRING_ALLOC_STATIC;    s->str = (char*)str;    } -  done: +     add_ref(s);    }       return s;   }      /*    * This function assumes that the shift size is already the minimum it    * can be.    */
pike.git/src/stralloc.c:878:    if(s2)    {    free_string(s);    s = s2;    add_ref(s);    }else{    link_pike_string(s, h);    }       return s; -  +    }      /*    * This function checks if the shift size can be decreased before    * entering the string in the shared string table    */   PMOD_EXPORT struct pike_string *end_shared_string(struct pike_string *s)   {    struct pike_string *s2;   
pike.git/src/stralloc.c:943: Inside #if defined(PIKE_DEBUG)
   struct pike_string *tmp;   #ifdef PIKE_DEBUG    if(len > str->len)    Pike_fatal("Cannot extend string here!\n");   #endif    tmp = make_shared_binary_pcharp(MKPCHARP_STR(str),len);    free_string(str);    return tmp;   }    -  +    PMOD_EXPORT struct pike_string * debug_make_shared_binary_string(const char *str,size_t len)   {    struct pike_string *s;    ptrdiff_t h = StrHash(str, len);       s = internal_findstring(str,len,0,h);    if (!s)    {    s=begin_shared_string(len);    memcpy(s->str, str, len);
pike.git/src/stralloc.c:978:    case 1:    return make_shared_binary_string1((p_wchar1 *)(str.ptr), len);    case 2:    return make_shared_binary_string2((p_wchar2 *)(str.ptr), len);   #ifdef PIKE_DEBUG    default:    Pike_fatal("Unknown string width!\n");   #endif    }    /* NOT REACHED */ -  return NULL; /* Keep the compiler happy */ +  return NULL; /* Keep the compiler happy */   }      PMOD_EXPORT struct pike_string * debug_make_shared_pcharp(const PCHARP str)   {    return debug_make_shared_binary_pcharp(str, pcharp_strlen(str));   }      PMOD_EXPORT struct pike_string * debug_make_shared_binary_string0(const p_wchar0 *str,size_t len)   {    return debug_make_shared_binary_string((const char *)str, len);
pike.git/src/stralloc.c:1082:   {    INT32 len;    for(len=0;str[len];len++);    return debug_make_shared_binary_string2(str,len);   }      /*** Free strings ***/      static void unlink_pike_string(struct pike_string *s)   { -  size_t h = HMODULO(s->hval); -  struct pike_string *tmp = base_table[h], *p = NULL; +  size_t h=HMODULO(s->hval); +  struct pike_string *tmp=base_table[h], *p=NULL;       while( tmp )    {    if( tmp == s )    {    if( p )    p->next = s->next;    else    base_table[h] = s->next;    break;    }    p = tmp;    tmp = tmp->next;    }       if( !tmp )    Pike_fatal("unlink on non-shared string\n");       s->next=(struct pike_string *)(ptrdiff_t)-1; -  +     num_strings--;    s->flags |= STRING_NOT_SHARED;   }      PMOD_EXPORT void do_free_string(struct pike_string *s)   {    if (s)    free_string(s);   }   
pike.git/src/stralloc.c:1150:    }   #endif    if (!(s->flags & STRING_NOT_SHARED))    unlink_pike_string(s);    if (s->flags & STRING_CLEAR_ON_EXIT)    guaranteed_memset(s->str, 0, s->len<<s->size_shift);    free_unlinked_pike_string(s);    GC_FREE_SIMPLE_BLOCK(s);   }    +    void do_really_free_string(struct pike_string *s)   {    if (s)    really_free_string(s);   }      PMOD_EXPORT void debug_free_string(struct pike_string *s)   {    if(!sub_ref(s))    really_free_string(s);   }    -  +    /*    * String table status    */   struct pike_string *add_string_status(int verbose)   {    struct string_builder s;    init_string_builder(&s, 0);       if (verbose)    {
pike.git/src/stralloc.c:1184:    long alloced_bytes[8] = {0,0,0,0,0,0,0,0};    long num_distinct_strings[8] = {0,0,0,0,0,0,0,0};    long bytes_distinct_strings[8] = {0,0,0,0,0,0,0,0};    long overhead_bytes[8] = {0,0,0,0,0,0,0,0};    unsigned INT32 e;    struct pike_string *p;    for(e=0;e<htable_size;e++)    {    for(p=base_table[e];p;p=p->next)    { -  int key = p->size_shift; +  int key = p->size_shift + (string_is_malloced(p)?4:0);    num_distinct_strings[key]++;    alloced_bytes[key] += p->refs*sizeof(struct pike_string);    alloced_strings[key] += p->refs;    if (string_is_block_allocated(p)) {    alloced_bytes[key] +=    p->refs*sizeof(struct pike_string);    } else {    alloced_bytes[key] +=    p->refs*DO_ALIGN((p->len+3) << p->size_shift,sizeof(void *));    }
pike.git/src/stralloc.c:1272:    }    }   /*    sprintf(b,"Searches: %ld Average search length: %6.3f\n",    (long)num_str_searches, (double)search_len / num_str_searches);    my_strcat(b);   */    return finish_string_builder(&s);   }    - /*** PIKE_DEBUG ***/ +    #ifdef PIKE_DEBUG      static long last_stralloc_verify=0;   extern long current_do_debug_cycle;      PMOD_EXPORT void check_string(struct pike_string *s)   {    if(current_do_debug_cycle == last_stralloc_verify)    {    if(debug_findstring(s) !=s)
pike.git/src/stralloc.c:1526:    * This can be used by eg replace_many() to speed up the comparisons.    */   ptrdiff_t generic_find_binary_prefix(const char *a,    ptrdiff_t alen, int asize,    const char *b,    ptrdiff_t blen, int bsize)   {    ptrdiff_t pos;    ptrdiff_t len = MINIMUM(alen, blen);    switch(TWO_SIZES(asize, bsize)) { - #define CASE(AZ, BZ) \ -  case TWO_SIZES(AZ, BZ): { \ -  PIKE_CONCAT(p_wchar, AZ) *a_arr = \ -  (PIKE_CONCAT(p_wchar, AZ) *)a; \ -  PIKE_CONCAT(p_wchar, BZ) *b_arr = \ -  (PIKE_CONCAT(p_wchar, BZ) *)b; \ -  for (pos=0; pos<len; pos++) { \ -  if (a_arr[pos] == b_arr[pos]) \ -  continue; \ -  if (a_arr[pos] < b_arr[pos]) \ -  return ~pos; \ -  return pos+1; \ -  } \ + #define CASE(AZ, BZ) \ +  case TWO_SIZES(AZ, BZ): { \ +  PIKE_CONCAT(p_wchar, AZ) *a_arr = \ +  (PIKE_CONCAT(p_wchar, AZ) *)a; \ +  PIKE_CONCAT(p_wchar, BZ) *b_arr = \ +  (PIKE_CONCAT(p_wchar, BZ) *)b; \ +  for (pos=0; pos<len; pos++) { \ +  if (a_arr[pos] == b_arr[pos]) \ +  continue; \ +  if (a_arr[pos] < b_arr[pos]) \ +  return ~pos; \ +  return pos+1; \ +  } \    } break    CASE(0,0);    CASE(0,1);    CASE(0,2);    CASE(1,0);    CASE(1,1);    CASE(1,2);    CASE(2,0);    CASE(2,1);    CASE(2,2);
pike.git/src/stralloc.c:1572:   /* Does not take locale into account */   PMOD_EXPORT ptrdiff_t my_quick_strcmp(const struct pike_string *a,    const struct pike_string *b)   {    if(a==b) return 0;       return generic_quick_binary_strcmp(a->str, a->len, a->size_shift,    b->str, b->len, b->size_shift);   }    +    struct pike_string *realloc_unlinked_string(struct pike_string *a,    ptrdiff_t size)   {    char * s = NULL;    size_t nbytes = (size_t)(size+1) << a->size_shift;    size_t obytes = (size_t)(a->len+1) << a->size_shift;    - #define TWO(A,B) ((A<<8)|B) +  if( size < a->len && size-a->len<(signed)sizeof(void*) ) +  goto done;    -  -  switch (TWO(a->alloc_type, (nbytes <= sizeof(struct pike_string))) ) +  if( nbytes < sizeof(struct pike_string) )    { -  case TWO(STRING_ALLOC_MALLOC,0): // malloc->malloc -  s=xrealloc(a->str, nbytes); -  break; -  case TWO(STRING_ALLOC_BA,0): // short->malloc -  s = xalloc(nbytes); -  a->alloc_type = STRING_ALLOC_MALLOC; -  memcpy(s, a->str, obytes); -  ba_free(&string_allocator, a->str); -  break; -  case TWO(STRING_ALLOC_MALLOC,1): // malloc -> short +  if( a->alloc_type == STRING_ALLOC_BA ) +  goto done;    s = ba_alloc(&string_allocator); -  +  memcpy(s,a->str,nbytes); +  free_string_content(a);    a->alloc_type = STRING_ALLOC_BA; -  memcpy(s, a->str, nbytes); -  free(a->str); -  break; -  case TWO(STRING_ALLOC_BA,1): // both are short -  goto done; -  case TWO(STRING_ALLOC_STATIC,0): // static -> malloc +  } +  else if( a->alloc_type == STRING_ALLOC_MALLOC) +  { +  s = xrealloc(a->str,nbytes); +  } +  else +  {    s = xalloc(nbytes); -  +  memcpy(s,a->str,MINIMUM(nbytes,obytes)); +  free_string_content(a);    a->alloc_type = STRING_ALLOC_MALLOC; -  memcpy(s, a->str, obytes); -  break; -  case TWO(STRING_ALLOC_STATIC,1): // static -> short -  s = ba_alloc(&string_allocator); -  a->alloc_type = STRING_ALLOC_BA; -  memcpy(s, a->str, obytes); -  break; -  case TWO(STRING_ALLOC_SUBSTRING,0): -  case TWO(STRING_ALLOC_SUBSTRING,1): -  Pike_fatal("This should not happen, substrings are never unlinked.\n"); -  break; -  default: -  Pike_fatal("encountered string with unknown allocation type %d\n", -  a->alloc_type); -  break; +     } - #undef TWO +     a->str = s;   done:    a->len=size;    low_set_index(a,size,0);       return a;   }    -  +    /* Returns an unlinked string ready for end_shared_string */   static struct pike_string *realloc_shared_string(struct pike_string *a,    ptrdiff_t size)   { -  if(string_may_modify(a)) +  if(string_may_modify_len(a))    {    unlink_pike_string(a);    return realloc_unlinked_string(a, size);    }else{    struct pike_string *r=begin_wide_shared_string(size,a->size_shift);    MEMCPY(r->str, a->str, a->len<<a->size_shift);    r->flags |= a->flags & STRING_CHECKED_MASK;    r->min = a->min;    r->max = a->max;    free_string(a);    return r;    }   }    - struct pike_string *new_realloc_shared_string(struct pike_string *a, INT32 size, int shift) + struct pike_string *new_realloc_shared_string(struct pike_string *a, INT32 size, enum size_shift shift)   {    struct pike_string *r;    if(shift == a->size_shift) return realloc_shared_string(a,size);       r=begin_wide_shared_string(size,shift);    pike_string_cpy(MKPCHARP_STR(r),a);    r->flags |= (a->flags & STRING_CHECKED_MASK);    r->min = a->min;    r->max = a->max;    free_string(a);
pike.git/src/stralloc.c:1789:          /* We now know that the string has the right character size */    if(string_may_modify(a))    {    /* One ref - destructive mode */       unlink_pike_string(a);    low_set_index(a, index, c);    CLEAR_STRING_CHECKED(a); -  +     if((((unsigned int)index) >= hash_prefix_len) && (index < a->len-8) )    {    struct pike_string *old;    /* Doesn't change hash value - sneak it in there */   #ifdef PIKE_DEBUG    if (wrong_hash(a)) {    Pike_fatal("Broken hash optimization.\n");    }   #endif    old = internal_findstring(a->str, a->len, a->size_shift, a->hval);
pike.git/src/stralloc.c:1936:       if(!r) return -1;   #ifdef PIKE_DEBUG    if((r < haystack->str) ||    (r - haystack->str)>>haystack->size_shift > haystack->len)    Pike_fatal("string_search did a bobo!\n");   #endif    return (r-haystack->str)>>haystack->size_shift;   }    - static struct pike_string *make_shared_substring0( struct pike_string *s, + static struct pike_string *make_shared_substring( struct pike_string *s,    ptrdiff_t start, -  ptrdiff_t len) +  ptrdiff_t len, +  enum size_shift shift)   {    struct pike_string *existing;    struct substring_pike_string *res; -  if( (existing = binary_findstring( s->str+start, len )) ) +  void *strstart = s->str+(start<<shift); +  size_t hval = low_do_hash(strstart,len,shift); +  if( (existing = +  internal_findstring(strstart, len, shift, hval)) )    {    add_ref(existing);    return existing;    }    res = ba_alloc(&substring_allocator);    res->parent = s;    add_ref(s);    existing = &res->str;    -  existing->flags = STRING_NOT_HASHED|STRING_NOT_SHARED; +  existing->flags = STRING_NOT_SHARED; +  existing->size_shift = shift;    existing->alloc_type = STRING_ALLOC_SUBSTRING; -  existing->str = s->str+start; +  existing->struct_type = STRING_STRUCT_SUBSTRING; +  existing->hval = hval; +  existing->str = strstart;    existing->len = len;   #ifdef PIKE_DEBUG    if( existing->len + start != s->len )    Pike_fatal("Substrings must be terminated at end of string for now.\n");   #endif    existing->refs = 0; -  existing->size_shift = 0; +     add_ref(existing); -  link_pike_string(existing, -  StrHash(existing->str,existing->len)); -  -  return (struct pike_string *)existing; +  link_pike_string(existing,hval); +  return existing;   }         PMOD_EXPORT struct pike_string *string_slice(struct pike_string *s,    ptrdiff_t start,    ptrdiff_t len)   {   #ifdef PIKE_DEBUG    if(start < 0 || len<0 || start+len>s->len )    {
pike.git/src/stralloc.c:2001:    add_ref(s);    return s;    }       /* Actually create a substring. */       /* If the string to take a substring of is    a substring, take from the original. */    if( s->alloc_type == STRING_ALLOC_SUBSTRING )    { -  struct pike_string *pr= ((struct substring_pike_string*)s)->parent; -  if( pr ) -  { +  struct pike_string *pr= substring_content_string(s);    /* Note: If substrings are ever anywhere except at the end,    this might need to change.    */    start += s->str-pr->str;    s = pr;    } -  } +     -  if( (len+start == s->len) && !s->size_shift ) +  if( (len+start == s->len) +  && start < (s->len>>1) +  && (!s->size_shift +  || (s->size_shift==1 && +  find_magnitude1(((p_wchar1*)s->str)+start,len)==1) +  || (s->size_shift==2 && +  find_magnitude2(((p_wchar2*)s->str)+start,len)==2)))    { -  if( start < (s->len >>1) ) /* <50% waste. */ -  return make_shared_substring0( s, start, len ); +  /* If there is no change of maginute, make a substring. */ +  return make_shared_substring( s, start, len, s->size_shift );    }       switch(s->size_shift)    {    case 0:    return make_shared_binary_string((char *)STR0(s)+start,len);       case 1:    return make_shared_binary_string1(STR1(s)+start,len);   
pike.git/src/stralloc.c:2044:      /*** replace function ***/   typedef char *(* replace_searchfunc)(void *,void *,size_t);   PMOD_EXPORT struct pike_string *string_replace(struct pike_string *str,    struct pike_string *del,    struct pike_string *to)   {    struct pike_string *ret;    char *s,*tmp,*end;    PCHARP r; -  int shift; +  enum size_shift shift;    SearchMojt mojt;    ONERROR mojt_uwp;    replace_searchfunc f = (replace_searchfunc)0;       if(!str->len || !string_range_contains_string(str, del))    {    add_ref(str);    return str;    }   
pike.git/src/stralloc.c:2423:    string_build_mkspace(s, chars, mag);    if(chars<0) s->known_shift=0;    ret = s->s->str + (s->s->len<<s->s->size_shift);    s->s->len += chars;    return ret;   }      PMOD_EXPORT void string_builder_putchar(struct string_builder *s, int ch)   {    ptrdiff_t i; -  int mag = min_magnitude(ch); +  enum size_shift mag = min_magnitude(ch);       string_build_mkspace(s, 1, mag);    if (mag > s->known_shift) {    s->known_shift = mag;    }    i = s->s->len++;    low_set_index(s->s,i,ch);   }      PMOD_EXPORT void string_builder_putchars(struct string_builder *s, int ch,    ptrdiff_t count)   {    ptrdiff_t len = s->s->len; -  int mag = min_magnitude(ch); +  enum size_shift mag = min_magnitude(ch);       /* This is not really expected to happen. But since we are doing    * memset here, a negative argument should be avoided. */    if (count < 0)    Pike_fatal("Non-positive count in call to string_builder_putchars().\n");    if (!count) return;       string_build_mkspace(s, count, mag);    if (mag > s->known_shift) {    s->known_shift = mag;
pike.git/src/stralloc.c:2520:   #endif    convert_1_to_2 (STR2(s->s)+s->s->len, str, len);    }    s->s->len += len;   }      PMOD_EXPORT void string_builder_binary_strcat2(struct string_builder *s,    const p_wchar2 *str, ptrdiff_t len)   {    if (s->s->size_shift < 2) { -  int shift = find_magnitude2 (str, len); +  enum size_shift shift = find_magnitude2 (str, len);       if (shift > s->s->size_shift) {    string_build_mkspace (s, len, shift);    if (shift == 1)    convert_2_to_1 (STR1(s->s) + s->s->len, str, len);    else {   #ifdef PIKE_DEBUG    if (shift != 2) Pike_fatal ("Uhh.. Like, what? (%d)\n", shift);   #endif    convert_2_to_2 (STR2(s->s) + s->s->len, str, len);
pike.git/src/stralloc.c:2561:    convert_2_to_2 (STR2(s->s) + s->s->len, str, len);    }       s->s->len += len;   }      PMOD_EXPORT void string_builder_append(struct string_builder *s,    const PCHARP from,    ptrdiff_t len)   { -  int shift = from.shift; +  enum size_shift shift = from.shift;    if (shift > s->s->size_shift) {    if (shift == 1) {    shift = find_magnitude1((p_wchar1 *)from.ptr, len);    } else {    shift = find_magnitude2((p_wchar2 *)from.ptr, len);    }    if (shift > s->known_shift)    s->known_shift = shift;    }    string_build_mkspace(s, len, shift);
pike.git/src/stralloc.c:2583:    s->s->len+=len;   }      PMOD_EXPORT void string_builder_fill(struct string_builder *s,    ptrdiff_t howmany,    const PCHARP from,    ptrdiff_t len,    ptrdiff_t offset)   {    ptrdiff_t tmp; -  int shift; +  enum size_shift shift;      #ifdef PIKE_DEBUG    if(len<=0)    Pike_fatal("Cannot fill with zero length strings!\n");   #endif    if(howmany<=0) return;       if(!s->s->size_shift &&    len == 1 &&    (!from.shift || !min_magnitude(EXTRACT_PCHARP(from))))
pike.git/src/stralloc.c:3314:    else    return (long) val;    }   }      int wide_string_to_svalue_inumber(struct svalue *r,    void * str,    void *ptr,    int base,    ptrdiff_t maxlength, -  int shift) +  enum size_shift shift)   {    PCHARP tmp;    int ret=pcharp_to_svalue_inumber(r,    MKPCHARP(str,shift),    &tmp,    base,    maxlength);    if(ptr) *(p_wchar0 **)ptr=tmp.ptr;    return ret;   }      int safe_wide_string_to_svalue_inumber(struct svalue *r,    void * str,    void *ptr,    int base,    ptrdiff_t maxlength, -  int shift) +  enum size_shift shift)   /* For use from the lexer where we can't let errors be thrown. */   {    PCHARP tmp;    JMP_BUF recovery;    int ret = 0;       free_svalue (&throw_value);    mark_free_svalue (&throw_value);       if (SETJMP (recovery)) {