pike.git / src / array.c

version» Context lines:

pike.git/src/array.c:1:   /*   || This file is part of Pike. For copyright information see COPYRIGHT.   || Pike is distributed under GPL, LGPL and MPL. See the file COPYING   || for more information. - || $Id$ +    */      #include "global.h"   #include "svalue.h"   #include "array.h"   #include "object.h"   #include "las.h"   #include "stralloc.h"   #include "interpret.h"   #include "opcodes.h"   #include "pike_error.h"   #include "pike_types.h"   #include "fsort.h"   #include "builtin_functions.h"   #include "pike_memory.h"   #include "gc.h"   #include "main.h" - #include "pike_security.h" +    #include "stuff.h" - #include "bignum.h" +    #include "cyclic.h"   #include "multiset.h"   #include "mapping.h"      /** The empty array. */   PMOD_EXPORT struct array empty_array=   {    PIKE_CONSTANT_MEMOBJ_INIT(1, PIKE_T_ARRAY), /* Never free */    &weak_empty_array, /* Next */    0, /* previous */
pike.git/src/array.c:86:    add_ref(&empty_array);    return &empty_array;    }       /* Limits size to (1<<29)-4 */    if( (size_t)(size+extra_space-1) >    (LONG_MAX-sizeof(struct array))/sizeof(struct svalue) )    Pike_error("Too large array (size %ld exceeds %ld).\n",    (long)(size+extra_space-1),    (long)((LONG_MAX-sizeof(struct array))/sizeof(struct svalue)) ); -  v=(struct array *)malloc(sizeof(struct array)+ +  v=malloc(sizeof(struct array)+    (size+extra_space-1)*sizeof(struct svalue));    if(!v)    Pike_error(msg_out_of_mem_2, sizeof(struct array)+    (size+extra_space-1)*sizeof(struct svalue));       GC_ALLOC(v);          if (size+extra_space)    /* for now, we don't know what will go in here */    v->type_field = BIT_MIXED | BIT_UNFINISHED;    else    v->type_field = 0;    v->flags=0;    -  v->malloced_size = DO_NOT_WARN((INT32)(size + extra_space)); +  v->malloced_size = (INT32)(size + extra_space);    v->item=v->real_item; -  v->size = DO_NOT_WARN((INT32)size); +  v->size = (INT32)size;    INIT_PIKE_MEMOBJ(v, T_ARRAY);    DOUBLELINK (first_array, v);       {    struct svalue *item = ITEM(v);    struct svalue *item_end = item + v->size;    while (item < item_end)    *item++ = svalue_int_zero;    }   
pike.git/src/array.c:127:      /**    * Free an array without freeing the values inside it.    * Any values inside of the array will be kept.    * @param v The array to be freed.    */   static void array_free_no_free(struct array *v)   {    DOUBLEUNLINK (first_array, v);    -  free((char *)v); +  free(v);       GC_FREE(v);   }      /**    * Free an array. Call this when the array has zero references.    * @param v The array to free.    */   PMOD_EXPORT void really_free_array(struct array *v)   {
pike.git/src/array.c:170:   /**    * Decrement the references (and free if unused) an array if it is not null.    */   PMOD_EXPORT void do_free_array(struct array *a)   {    if (a)    free_array(a);   }      /** +  * Free all elements in an array and set them to zero. +  */ + PMOD_EXPORT void clear_array(struct array *a) + { +  if (!a->size) return; +  free_svalues(ITEM(a), a->size, a->type_field); +  /* NB: We know that INT_T == 0. */ +  memset(ITEM(a), 0, a->size * sizeof(struct svalue)); +  a->type_field = BIT_INT; + } +  + /**    * Set the flags on an array. If the array is empty then only the    * weak flag is significant.    */   PMOD_EXPORT struct array *array_set_flags(struct array *a, int flags)   {    if (a->size)    a->flags = flags;    else {    free_array(a);    if (flags & ARRAY_WEAK_FLAG)
pike.git/src/array.c:381: Inside #if defined(PIKE_DEBUG)
   if(index<0 || index>v->size)    Pike_fatal("Illegal index in low level insert routine.\n");   #endif       /* Can we fit it into the existing block? */    if(v->refs<=1 && (v->malloced_size > v->size))    {    if ((v->item != v->real_item) &&    (((index<<1) < v->size) ||    ((v->item + v->size) == (v->real_item + v->malloced_size)))) { -  MEMMOVE((char *)(ITEM(v)-1), -  (char *)(ITEM(v)), -  index * sizeof(struct svalue)); +  memmove(ITEM(v)-1, ITEM(v), index * sizeof(struct svalue));    v->item--;    } else { -  MEMMOVE((char *)(ITEM(v)+index+1), -  (char *)(ITEM(v)+index), +  memmove(ITEM(v)+index+1, ITEM(v)+index,    (v->size-index) * sizeof(struct svalue));    }    assert_free_svalue (ITEM(v) + index);    v->size++;    }else{    struct array *ret;       ret = array_set_flags(allocate_array_no_init(v->size+1, v->size + 1),    v->flags);    ret->type_field = v->type_field;    -  MEMCPY(ITEM(ret), ITEM(v), sizeof(struct svalue) * index); -  MEMCPY(ITEM(ret)+index+1, ITEM(v)+index, +  memcpy(ITEM(ret), ITEM(v), sizeof(struct svalue) * index); +  memcpy(ITEM(ret)+index+1, ITEM(v)+index,    sizeof(struct svalue) * (v->size-index));    assert_free_svalue (ITEM(ret) + index);    if (v->refs == 1) {    /* Optimization: Steal the references. */    v->size = 0;    } else if (v->type_field & BIT_REF_TYPES) {    /* Adjust the references. */    int e = v->size;    struct svalue *s = ITEM(ret);    while (e--) { -  if (TYPEOF(*s) <= MAX_REF_TYPE) add_ref(s->u.dummy); +  if (REFCOUNTED_TYPE(TYPEOF(*s))) add_ref(s->u.dummy);    s++;    }    }    free_array(v);    v=ret;    }       array_set_index_no_free (v,index,s);       return v;   }      /*    * lval += ({ @args });    * -  * Stack is lvalue followed by arguments. +  * Stack is lvalue followed by a zero placeholder followed by arguments.    */   void o_append_array(INT32 args)   {    struct svalue *lval = Pike_sp - args;    struct svalue *val = lval + 2; -  +  int lval_type;   #ifdef PIKE_DEBUG    if (args < 3) {    Pike_fatal("Too few arguments to o_append_array(): %d\n", args);    }   #endif    args -= 3;    /* Note: val should always be a zero here! */ -  lvalue_to_svalue_no_free(val, lval); +  lval_type = lvalue_to_svalue_no_free(val, lval);       if (TYPEOF(*val) == T_ARRAY) {    struct svalue tmp;    struct array *v = val->u.array; -  +  /* simple case: if refs == 2 and there is space, just add the +  element and do not do the assign. This can be done because the +  lvalue already has the array as it's value. +  */ +  if( (v->refs == 2) && (lval_type != PIKE_T_GET_SET) ) { +  if ((TYPEOF(*lval) == T_OBJECT) && +  lval->u.object->prog && +  ((FIND_LFUN(lval->u.object->prog, LFUN_ASSIGN_INDEX) >= 0) || +  (FIND_LFUN(lval->u.object->prog, LFUN_ASSIGN_ARROW) >= 0))) { +  /* There's a function controlling assignments in this object, +  * so we can't alter the array in place. +  */ +  } else if( v->real_item+v->malloced_size >= v->item+v->size+args ) { +  struct svalue *from = val+1; +  int i; +  for( i = 0; i<args; i++,from++ ) +  { +  v->item[v->size++] = *from; +  v->type_field |= 1<<TYPEOF(*from); +  } +  Pike_sp -= args; +  stack_pop_2_elems_keep_top(); +  return; +  } +  }    /* This is so that we can minimize the number of references    * to the array, and be able to use destructive operations.    * It's done by freeing the old reference to foo after it has been    * pushed on the stack. That way foo can have only 1 reference if we    * are lucky, and then the low array manipulation routines can    * be destructive if they like.    */    SET_SVAL(tmp, PIKE_T_INT, NUMBER_NUMBER, integer, 0);    assign_lvalue(lval, &tmp);   
pike.git/src/array.c:538:    free_svalues(ITEM(v) + size, v->size - size, v->type_field);    v->size=size;       if(size*4 < v->malloced_size + 4) /* Should we realloc it? */    {    a = array_set_flags(allocate_array_no_init(size, 0), v->flags);    if (a->size) {    a->type_field = v->type_field;    }    -  MEMCPY(ITEM(a), ITEM(v), size*sizeof(struct svalue)); +  memcpy(ITEM(a), ITEM(v), size*sizeof(struct svalue));    v->size=0;    free_array(v);    return a;    }else{    return v;    }   }      /**    * Resize an array destructively, with the exception that a may be one
pike.git/src/array.c:577:    {    for(;a->size < size; a->size++)    {    SET_SVAL(ITEM(a)[a->size], T_INT, NUMBER_NUMBER, integer, 0);    }    a->type_field |= BIT_INT;    return a;    } else {    struct array *ret;    ret = array_set_flags(low_allocate_array(size, size + 1), a->flags); -  MEMCPY(ITEM(ret), ITEM(a), sizeof(struct svalue)*a->size); -  ret->type_field = DO_NOT_WARN((TYPE_FIELD)(a->type_field | BIT_INT)); +  memcpy(ITEM(ret), ITEM(a), sizeof(struct svalue)*a->size); +  ret->type_field = (TYPE_FIELD)(a->type_field | BIT_INT);    a->size=0;    free_array(a);    return ret;    }    } else {    return array_shrink(a, size);    }   }      /**
pike.git/src/array.c:620:    /* NOTE: The following uses the fact that array_set_flags()    * will reallocate the array if it has zero size!    */    return array_set_flags(v, v->flags);    } else if(v->size*4 + 4 < v->malloced_size ) /* Should we realloc it? */    {    a = array_set_flags(allocate_array_no_init(v->size-1, 0), v->flags);    a->type_field = v->type_field;       if(index>0) -  MEMCPY(ITEM(a), ITEM(v), index*sizeof(struct svalue)); +  memcpy(ITEM(a), ITEM(v), index*sizeof(struct svalue));    if(v->size-index>1) -  MEMCPY(ITEM(a)+index, +  memcpy(ITEM(a)+index,    ITEM(v)+index+1,    (v->size-index-1)*sizeof(struct svalue));    v->size=0;    free_array(v);    return a;    } else {    if(v->size-index>1)    { -  MEMMOVE((char *)(ITEM(v)+index), -  (char *)(ITEM(v)+index+1), +  memmove(ITEM(v)+index, ITEM(v)+index+1,    (v->size-index-1)*sizeof(struct svalue));    }    v->size--;    return v;    }   }    -  + static ptrdiff_t fast_array_search( struct array *v, struct svalue *s, ptrdiff_t start ) + { +  ptrdiff_t e; +  struct svalue *ip = ITEM(v); +  for(e=start;e<v->size;e++) +  if(is_eq(ip+e,s)) +  return e; +  return -1; + } +    /**    * Search for in svalue in an array.    * @param v the array to search    * @param s the value to search for    * @param start the index to start search at    * @return the index if found, -1 otherwise    */   PMOD_EXPORT ptrdiff_t array_search(struct array *v, struct svalue *s,    ptrdiff_t start)   { -  ptrdiff_t e; -  +    #ifdef PIKE_DEBUG    if(start<0)    Pike_fatal("Start of find_index is less than zero.\n");   #endif -  -  check_destructed(s); -  +    #ifdef PIKE_DEBUG    if(d_flag > 1) array_check_type_field(v);   #endif -  +  check_destructed(s); +     /* Why search for something that is not there?    * however, we must explicitly check for searches    * for destructed objects/functions    */    if((v->type_field & (1 << TYPEOF(*s))) ||    (UNSAFE_IS_ZERO(s) && (v->type_field & (BIT_FUNCTION|BIT_OBJECT))) ||    ( (v->type_field | (1<<TYPEOF(*s))) & BIT_OBJECT )) /* for overloading */ -  { -  if(start) -  { -  for(e=start;e<v->size;e++) -  if(is_eq(ITEM(v)+e,s)) return e; -  }else{ -  TYPE_FIELD t=0; -  for(e=0;e<v->size;e++) -  { -  if(is_eq(ITEM(v)+e,s)) return e; -  t |= 1<<TYPEOF(ITEM(v)[e]); -  } -  v->type_field=t; -  } -  } +  return fast_array_search( v, s, start );    return -1;   }      /**    * Slice a piece of an array (conditionally destructively)    * @param v the array to slice    * @param start the beginning element to be included    * @param end the element beyond the end of the slice    * @return an array consisting of v[start..end-1]    */
pike.git/src/array.c:878:      /* The sort is stable. */   INT32 *get_order(struct array *v, cmpfun fun)   {    INT32 e, *current_order;    ONERROR tmp;       if(!v->size) return 0;       /* Overlow safe: ((1<<29)-4)*4 < ULONG_MAX */ -  current_order=(INT32 *)xalloc(v->size * sizeof(INT32)); +  current_order=xalloc(v->size * sizeof(INT32));    SET_ONERROR(tmp, free, current_order);    for(e=0; e<v->size; e++) current_order[e]=e;       get_order_fsort(current_order,    current_order+v->size-1,    fun,    ITEM(v));       UNSET_ONERROR(tmp);    return current_order;
pike.git/src/array.c:926:    fun + p->inherits[SUBTYPEOF(*a)].identifier_level, 1);    if(!UNSAFE_IS_ZERO(Pike_sp-1))    {    pop_stack();    return 1;    }    pop_stack();    default_res = CMPFUN_UNORDERED;    }    -  if ((fun = FIND_LFUN(p->inherits[SUBTYPEOF(*a)].prog, LFUN_EQ)) != -1) { +  /* NB: It's not a good idea to use LFUN_EQ here if +  * there is neither LFUN_LT nor LFUN_GT, since +  * the sorting order may get confused, which +  * will cause merge_array_with_order() to fail. +  */ +  if ((default_res == CMPFUN_UNORDERED) && +  (fun = FIND_LFUN(p->inherits[SUBTYPEOF(*a)].prog, LFUN_EQ)) != -1) {    push_svalue(b);    apply_low(a->u.object,    fun + p->inherits[SUBTYPEOF(*a)].identifier_level, 1);    if (!UNSAFE_IS_ZERO(Pike_sp-1)) {    pop_stack();    return 0;    }    pop_stack();    }    }
pike.git/src/array.c:965:    fun + p->inherits[SUBTYPEOF(*b)].identifier_level, 1);    if(!UNSAFE_IS_ZERO(Pike_sp-1))    {    pop_stack();    return -1;    }    pop_stack();    default_res = CMPFUN_UNORDERED;    }    -  if ((fun = FIND_LFUN(p->inherits[SUBTYPEOF(*b)].prog, LFUN_EQ)) != -1) { +  /* NB: It's not a good idea to use LFUN_EQ here if +  * there is neither LFUN_LT nor LFUN_GT, since +  * the sorting order may get confused, which +  * will cause merge_array_with_order() to fail. +  */ +  if ((default_res == CMPFUN_UNORDERED) && +  (fun = FIND_LFUN(p->inherits[SUBTYPEOF(*b)].prog, LFUN_EQ)) != -1) {    push_svalue(a);    apply_low(b->u.object,    fun + p->inherits[SUBTYPEOF(*b)].identifier_level, 1);    if (!UNSAFE_IS_ZERO(Pike_sp-1)) {    pop_stack();    return 0;    }    pop_stack();    }    }
pike.git/src/array.c:1083:       case T_OBJECT:    case T_FUNCTION:    return obj_or_func_cmp (a, b);       default:    if(a->u.refs < b->u.refs) return -1;    if(a->u.refs > b->u.refs) return 1;    return 0;    } -  /* NOT REACHED */ +    }      static int switch_svalue_cmpfun(const struct svalue *a, const struct svalue *b)   {    int typediff = TYPEOF(*a) - TYPEOF(*b);    if (typediff)    return typediff;       switch(TYPEOF(*a))    {
pike.git/src/array.c:1105:    if(a->u.integer < b->u.integer) return -1;    if(a->u.integer > b->u.integer) return 1;    return 0;       case T_FLOAT:    if(a->u.float_number < b->u.float_number) return -1;    if(a->u.float_number > b->u.float_number) return 1;    return 0;       case T_STRING: -  return DO_NOT_WARN((int)my_quick_strcmp(a->u.string, b->u.string)); +  return (int)my_quick_strcmp(a->u.string, b->u.string);       case T_OBJECT:    case T_FUNCTION:    return obj_or_func_cmp (a, b);       default:    if(a->u.refs < b->u.refs) return -1;    if(a->u.refs > b->u.refs) return 1;    return 0;    } -  /* NOT REACHED */ +    }      int alpha_svalue_cmpfun(const struct svalue *a, const struct svalue *b)   {    int typediff = TYPEOF(*a) - TYPEOF(*b);    if (typediff) {    if (TYPEOF(*a) == T_OBJECT || TYPEOF(*b) == T_OBJECT) {    int res = lfun_cmp (a, b);    if (res != -CMPFUN_UNORDERED) return res;    }
pike.git/src/array.c:1143:    if(a->u.integer < b->u.integer) return -1;    if(a->u.integer > b->u.integer) return 1;    return 0;       case T_FLOAT:    if(a->u.float_number < b->u.float_number) return -1;    if(a->u.float_number > b->u.float_number) return 1;    return 0;       case T_STRING: -  return DO_NOT_WARN((int)my_quick_strcmp(a->u.string, b->u.string)); +  return (int)my_quick_strcmp(a->u.string, b->u.string);       case T_ARRAY:    if(a==b) return 0;    if (!a->u.array->size)    if (!b->u.array->size) /* There are several different empty arrays. */    return 0;    else    return -1;    else    if (!b->u.array->size)
pike.git/src/array.c:1189:       case T_OBJECT:    case T_FUNCTION:    return obj_or_func_cmp (a, b);       default:    if(a->u.ptr < b->u.ptr) return -1;    if(a->u.ptr > b->u.ptr) return 1;    return 0;    } -  /* NOT REACHED */ +    }      #define CMP(X,Y) alpha_svalue_cmpfun(X,Y)   #define TYPE struct svalue   #define ID low_sort_svalues   #include "fsort_template.h"   #undef CMP   #undef TYPE   #undef ID   
pike.git/src/array.c:1267:    * get_alpha_order. */   PMOD_EXPORT INT32 *stable_sort_array_destructively(struct array *v)   {    INT32 *current_order;    ONERROR tmp;    int e;       if(!v->size) return NULL;       /* Overflow safe: ((1<<29)-4)*4 < ULONG_MAX */ -  current_order=(INT32 *)xalloc(v->size * sizeof(INT32)); +  current_order=xalloc(v->size * sizeof(INT32));    SET_ONERROR(tmp, free, current_order);    for(e=0; e<v->size; e++) current_order[e]=e;       low_stable_sort_svalues (0, v->size - 1, ITEM (v), current_order, v->size);       UNSET_ONERROR (tmp);    return current_order;   }      
pike.git/src/array.c:1417:    if(v->flags & ARRAY_LVALUE)    {    v->type_field=BIT_MIXED|BIT_UNFINISHED;    return BIT_MIXED|BIT_UNFINISHED;    }       t=0;       for(e=0; e<v->size; e++) {    check_svalue (ITEM(v) + e); -  t |= 1 << TYPEOF(ITEM(v)[e]); +  t |= BITOF(ITEM(v)[e]);    }      #ifdef PIKE_DEBUG    if(t & ~(v->type_field))    {    describe(v);    Pike_fatal("Type field out of order (old:0x%04x new:0x%04x)!\n",    v->type_field, t);    }   #endif
pike.git/src/array.c:1534:    }   #endif    if(!(a->type_field & b->type_field) &&    !((a->type_field | b->type_field) & BIT_OBJECT))    {    /* do smart optimizations */    switch(opcode)    {    case PIKE_ARRAY_OP_AND:    /* Trivially overflow safe */ -  ret=(INT32 *)xalloc(sizeof(INT32)); +  ret=xalloc(sizeof(INT32));    *ret=0;    return ret;       case PIKE_ARRAY_OP_SUB:    /* Overlow safe: ((1<<29)-4+1)*4 < ULONG_MAX */ -  ptr=ret=(INT32 *)xalloc(sizeof(INT32)*(a->size+1)); +  ptr=ret=xalloc(sizeof(INT32)*(a->size+1));    *(ptr++)=a->size;    for(i=0;i<a->size;i++) *(ptr++)=i;    return ret;    }    }       /* Note: The following is integer overflow safe as long as    * sizeof(struct svalue) >= 2*sizeof(INT32).    */ -  ptr=ret=(INT32 *)xalloc(sizeof(INT32)*(a->size + b->size + 1)); +  ptr=ret=xalloc(sizeof(INT32)*(a->size + b->size + 1));    SET_ONERROR(r, free,ret);    ptr++;       while(ap < a->size && bp < b->size)    {    i=set_svalue_cmpfun(ITEM(a)+ap,ITEM(b)+bp);    if(i < 0)    i=opcode >> 8;    else if(i > 0)    i=opcode;
pike.git/src/array.c:1573:       if(i & PIKE_ARRAY_OP_A) *(ptr++)=ap;    if(i & PIKE_ARRAY_OP_B) *(ptr++)=~bp;    if(i & PIKE_ARRAY_OP_SKIP_A) ap++;    if(i & PIKE_ARRAY_OP_SKIP_B) bp++;    }       if((opcode >> 8) & PIKE_ARRAY_OP_A) while(ap<a->size) *(ptr++)=ap++;    if(opcode & PIKE_ARRAY_OP_B) while(bp<b->size) *(ptr++)=~(bp++);    -  *ret = DO_NOT_WARN((INT32)(ptr-ret-1)); +  *ret = (INT32)(ptr-ret-1);       UNSET_ONERROR(r);       return ret;   }      /**    * This routine merges two arrays in the order specified by 'zipper'    * zipper normally produced by merge() above.    */
pike.git/src/array.c:1664: Inside #if 1 and #if defined(PIKE_DEBUG)
   }   #ifdef PIKE_DEBUG    if(d_flag>1)    check_array(v);   #endif    return v;    }    if (!v2 || (v->size > v2->size)) {    /* Got a potential candidate.    * -  * Optimize for maximum MEMMOVE() +  * Optimize for maximum memmove()    * (ie minimum assign_svalues_no_free()).    */    tmp2 = tmp;    v2 = v;    e2 = e;    }    }    tmp+=v->size;    }    if (v2) {    debug_malloc_touch(v2);    mark_free_svalue(argp + e2); -  MEMMOVE((char *)(v2->real_item + tmp2), (char *)ITEM(v2), +  memmove(v2->real_item + tmp2, ITEM(v2),    v2->size * sizeof(struct svalue));    v2->item = v2->real_item + tmp2;    for(tmp=e2-1;tmp>=0;tmp--)    {    v = argp[tmp].u.array;    debug_malloc_touch(v);    v2->type_field |= v->type_field;    assign_svalues_no_free(ITEM(v2) - v->size, ITEM(v),    v->size, v->type_field);    v2->item -= v->size;
pike.git/src/array.c:1754: Inside #if defined(PIKE_DEBUG)
   array_check_type_field(a);    array_check_type_field(b);    }   #endif       /* This could be done much better if I KNEW that    * the type fields didn't contain types that    * really aren't in the array    */    if(!(a->type_field & b->type_field) && -  !( (a->type_field | b->type_field) & BIT_OBJECT )) +  !( (a->type_field | b->type_field) & (BIT_OBJECT|BIT_FUNCTION) ))    return 0;       curr.pointer_a = a;    curr.pointer_b = b;    curr.next = p;       for( ;p ;p=p->next)    if(p->pointer_a == (void *)a && p->pointer_b == (void *)b)    return 1;   
pike.git/src/array.c:1871: Inside #if 0
   for (i = 1; i < *zipper + 1; i++)    fprintf (stderr, "%d ", zipper[i]);    fprintf (stderr, "\n");    }   #endif       fsort_with_order( (zipper+1), zipper+*zipper, array_merge_fun,    ordera, orderb );       ret=array_zip(tmpa,tmpb,zipper); -  UNSET_ONERROR(r3); free((char *)zipper); +  UNSET_ONERROR(r3); free(zipper);    UNSET_ONERROR(r2); free_array(tmpb);    UNSET_ONERROR(r1); free_array(tmpa); -  UNSET_ONERROR(r5); free((char *)orderb); -  UNSET_ONERROR(r4); free((char *)ordera); +  UNSET_ONERROR(r5); free(orderb); +  UNSET_ONERROR(r4); free(ordera);    return ret;   }         #define CMP(X,Y) set_svalue_cmpfun(X,Y)   #define TYPE struct svalue   #define ID set_sort_svalues   #include "fsort_template.h"   #undef CMP   #undef TYPE   #undef ID    -  - PMOD_EXPORT struct array *merge_array_without_order2(struct array *a, struct array *b,INT32 op) + /** Remove all instances of an svalue from an array + */ + static struct array *subtract_array_svalue(struct array *a, struct svalue *b)   { -  ONERROR r1,r2,r3,r4,r5; -  INT32 ap,bp,i; -  struct svalue *arra,*arrb; -  struct array *ret; +  size_t size = a->size; +  size_t from=0, to=0; +  TYPE_FIELD to_type = 1<<TYPEOF(*b); +  TYPE_FIELD type_field = 0; +  ONERROR ouch; +  struct svalue *ip=ITEM(a), *dp=ip; +  int destructive = 1;    - #ifdef PIKE_DEBUG -  if(d_flag > 1) +  if( size == 0 ) +  return copy_array(a); +  +  if( a->refs > 1 )    { -  array_check_type_field(a); -  array_check_type_field(b); -  } - #endif +  /* We only need to do anything if the value exists in the array. */ +  ptrdiff_t off = fast_array_search( a, b, 0 ); +  TYPE_FIELD tmp;    -  SET_ONERROR(r1,do_free_array,a); -  SET_ONERROR(r2,do_free_array,b); +  if( off == -1 ) +  /* We still need to return a new array. */ +  return copy_array(a);    -  if(a->refs==1 || !a->size) -  { -  arra=ITEM(a); -  }else{ -  /* Overlow safe: ((1<<29)-4)*8 < ULONG_MAX */ -  arra=(struct svalue *)xalloc(a->size*sizeof(struct svalue)); -  MEMCPY(arra,ITEM(a),a->size*sizeof(struct svalue)); -  SET_ONERROR(r3,free,arra); -  } +  /* In this case we generate a new array and modify that one. */ +  destructive = 0; +  from = (size_t)off; +  tmp = a->type_field; +  a = allocate_array_no_init(size-1,0); +  a->type_field = tmp; +  SET_ONERROR( ouch, do_free_array, a ); +  dp = ITEM(a);    -  if(b->refs==1 || !b->size) +  /* Copy the part of the array that is not modified first.. */ +  for( to=0; to<from; to++, ip++, dp++)    { -  arrb=ITEM(b); -  }else{ -  /* Overlow safe: ((1<<29)-4)*8 < ULONG_MAX */ -  arrb=(struct svalue *)xalloc(b->size*sizeof(struct svalue)); -  MEMCPY(arrb,ITEM(b),b->size*sizeof(struct svalue)); -  SET_ONERROR(r4,free,arrb); +  assign_svalue_no_free(dp, ip); +  type_field |= 1<<TYPEOF(*dp);    } -  +  a->size = from; +  }    -  set_sort_svalues(arra,arra+a->size-1); -  set_sort_svalues(arrb,arrb+b->size-1); + #define MATCH_COPY(X) do { \ +  if( X ) \ +  { /* include entry */ \ +  type_field|=1<<TYPEOF(*ip); \ +  if(!destructive) \ +  assign_svalue_no_free(dp,ip); \ +  else if(ip!=dp) \ +  *dp=*ip; \ +  dp++; \ +  if( !destructive ) a->size++; \ +  } \ +  else if( destructive ) \ +  free_svalue( ip ); \ +  } while(0)    -  ret=low_allocate_array(0,32); -  SET_ONERROR(r5,do_free_array,ret); -  ap=bp=0; +     -  while(ap < a->size && bp < b->size) +  if( UNSAFE_IS_ZERO( b ) )    { -  i=set_svalue_cmpfun(arra+ap,arrb+bp); -  if(i < 0) -  i=op >> 8; -  else if(i > 0) -  i=op; -  else -  i=op >> 4; +  /* Remove 0-valued elements. +  Rather common, so a special case is motivated.    -  if(i & PIKE_ARRAY_OP_A) ret=append_array(ret,arra+ap); -  if(i & PIKE_ARRAY_OP_B) ret=append_array(ret,arrb+bp); -  if(i & PIKE_ARRAY_OP_SKIP_A) ap++; -  if(i & PIKE_ARRAY_OP_SKIP_B) bp++; +  This saves time becase there is no need to check if 'b' is zero +  for each loop. +  */ +  for( ;from<size; from++, ip++ ) +  MATCH_COPY( !UNSAFE_IS_ZERO(ip) );    } -  -  if((op >> 8) & PIKE_ARRAY_OP_A) -  while(ap<a->size) -  ret=append_array(ret,arra + ap++); -  -  if(op & PIKE_ARRAY_OP_B) -  while(bp<b->size) -  ret=append_array(ret,arrb + bp++); -  -  UNSET_ONERROR(r5); -  -  if(arrb != ITEM(b)) +  else if((a->type_field & to_type) || ((a->type_field | to_type) & BIT_OBJECT))    { -  UNSET_ONERROR(r4); -  free((char *)arrb); +  for( ; from<size; from++, ip++ ) +  MATCH_COPY( !is_eq(ip,b) );    } -  -  if(arra != ITEM(a)) +  else /* b does not exist in the array. */    { -  UNSET_ONERROR(r3); -  free((char *)arra); +  add_ref(a); +  return a;    } -  + #undef MATCH_COPY    -  UNSET_ONERROR(r2); -  free_array(b); -  -  UNSET_ONERROR(r1); -  free_array(a); -  -  return ret; +  if( dp != ip ) +  { +  a->type_field = type_field; +  a->size = dp-ITEM(a);    }    -  +  if( !destructive ) +  UNSET_ONERROR( ouch ); +  else +  add_ref(a);    - /** merge two arrays without paying attention to the order -  * the elements has presently -  */ - PMOD_EXPORT struct array *merge_array_without_order(struct array *a, -  struct array *b, -  INT32 op) - { - #if 0 -  /* FIXME: If this routine is ever reinstated, it has to be -  * fixed to use ONERROR -  */ -  INT32 *zipper; -  struct array *tmpa,*tmpb,*ret; +  if( a->size ) +  return a;    -  if(ordera) { free((char *)ordera); ordera=0; } -  if(orderb) { free((char *)orderb); orderb=0; } -  -  ordera=get_set_order(a); -  tmpa=reorder_and_copy_array(a,ordera); -  free((char *)ordera); -  ordera=0; -  -  orderb=get_set_order(b); -  tmpb=reorder_and_copy_array(b,orderb); -  free((char *)orderb); -  orderb=0; -  -  zipper=merge(tmpa,tmpb,op); -  ret=array_zip(tmpa,tmpb,zipper); -  free_array(tmpa); -  free_array(tmpb); -  free((char *)zipper); -  return ret; -  - #else -  add_ref(a); -  add_ref(b); -  return merge_array_without_order2(a,b,op); - #endif +  free_array(a); +  add_ref(&empty_array); +  return &empty_array;   }      /** Subtract an array from another.   */   PMOD_EXPORT struct array *subtract_arrays(struct array *a, struct array *b)   {   #ifdef PIKE_DEBUG    if(d_flag > 1)    {    array_check_type_field(b);    }   #endif -  check_array_for_destruct(a); +  if( b->size == 1 ) +  return subtract_array_svalue( a, ITEM(b) );    -  if((a->type_field & b->type_field) || -  ((a->type_field | b->type_field) & BIT_OBJECT)) +  if(b->size && +  ((a->type_field & b->type_field) || +  ((a->type_field | b->type_field) & BIT_OBJECT)))    {    return merge_array_with_order(a, b, PIKE_ARRAY_OP_SUB);    }else{    if(a->refs == 1)    {    add_ref(a);    return a;    } -  return slice_array(a,0,a->size); +  return copy_array(a);    }   }    -  +    /** And two arrays together.    */   PMOD_EXPORT struct array *and_arrays(struct array *a, struct array *b)   {   #ifdef PIKE_DEBUG    if(d_flag > 1)    array_check_type_field(b);   #endif    check_array_for_destruct(a);   
pike.git/src/array.c:2166:   }      /** Push elements of an array onto the stack. The array will be freed.    */   PMOD_EXPORT void push_array_items(struct array *a)   {    check_stack(a->size);    check_array_for_destruct(a);    if(a->refs == 1)    { -  MEMCPY(Pike_sp,ITEM(a),sizeof(struct svalue)*a->size); +  memcpy(Pike_sp,ITEM(a),sizeof(struct svalue)*a->size);    Pike_sp += a->size;    a->size=0;    free_array(a);    }else{    assign_svalues_no_free(Pike_sp, ITEM(a), a->size, a->type_field);    Pike_sp += a->size;    free_array(a);    }   }   
pike.git/src/array.c:2263:    * Pops a number of arguments off of the stack an puts them in an array.    * The 'top' of the stack will be the last element in the array.    * @param args The number of arguments to aggregate.    */   PMOD_EXPORT struct array *aggregate_array(INT32 args)   {    struct array *a;       a=allocate_array_no_init(args,0);    if (args) { -  MEMCPY((char *)ITEM(a),(char *)(Pike_sp-args),args*sizeof(struct svalue)); +  memcpy(ITEM(a),Pike_sp-args,args*sizeof(struct svalue));    array_fix_type_field (a);    Pike_sp-=args;    DO_IF_DMALLOC(while(args--) dmalloc_touch_svalue(Pike_sp + args));    }    return a;   }      /** Add an element to the end of an array by resizing the array.    *    * @param a the array to be appended    * @param s the value to be added to the new element in the array    */   PMOD_EXPORT struct array *append_array(struct array *a, struct svalue *s)   { -  a=resize_array(a,a->size+1); -  array_set_index(a, a->size-1, s); +  INT32 size = a->size; +  a=resize_array(a, size+1); +  array_set_index(a, size, s);    return a;   }    -  + /** Automap assignments +  * This implements X[*] = ...[*].. +  * Assign elements in a at @level to elements from b at the same @level. +  * This will not actually modify any of the arrays, only change the +  * values in them. +  */ + void assign_array_level( struct array *a, struct array *b, int level ) + { +  if( a->size != b->size ) +  /* this should not really happen. */ +  Pike_error("Source and destination differs in size in automap?!\n"); +  +  if( level > 1 ) +  { +  /* recurse. */ +  INT32 i; +  for( i=0; i<a->size; i++ ) +  { +  if( TYPEOF(a->item[i]) != PIKE_T_ARRAY ) +  Pike_error("Too many automap levels.\n"); +  if( TYPEOF(b->item[i]) != PIKE_T_ARRAY ) /* obscure messages much? */ +  Pike_error("Not enough levels of mapping in RHS\n"); +  assign_array_level( a->item[i].u.array, b->item[i].u.array, level-1 ); +  } +  } +  else { +  assign_svalues( a->item, b->item, a->size, +  a->type_field|b->type_field ); +  a->type_field = b->type_field; +  } + } +  + /* Assign all elemnts in a at level to b. +  * This implements X[*] = expression without automap. +  */ + void assign_array_level_value( struct array *a, struct svalue *b, int level ) + { +  INT32 i; +  if( level > 1 ) +  { +  /* recurse. */ +  for( i=0; i<a->size; i++ ) +  { +  if( TYPEOF(a->item[i]) != PIKE_T_ARRAY ) +  Pike_error("Too many automap levels.\n"); +  assign_array_level_value( a->item[i].u.array, b, level-1 ); +  } +  } +  else +  { +  if( a->type_field & BIT_REF_TYPES ) free_mixed_svalues( a->item, a->size ); +  if( REFCOUNTED_TYPE(TYPEOF(*b)) ) *b->u.refs+=a->size; +  for( i=0; i<a->size; i++) +  a->item[i] = *b; +  a->type_field = 1 << TYPEOF(*b); +  } + } +    typedef char *(* explode_searchfunc)(void *,void *,size_t);      /** Explode a string into an array by a delimiter.    *    * @param str the string to be split    * @param del the string to split str by    * @returns an array containing the elements of the split string    */   PMOD_EXPORT struct array *explode(struct pike_string *str,    struct pike_string *del)
pike.git/src/array.c:2319:    SET_SVAL(ITEM(ret)[e], T_STRING, 0, string, string_slice(str,e,1));    }    }else{    SearchMojt mojt;    ONERROR uwp;    explode_searchfunc f = (explode_searchfunc)0;       s=str->str;    end=s+(str->len << str->size_shift);    -  ret=allocate_array(10); +  ret=allocate_array(2);    ret->size=0;       mojt=compile_memsearcher(MKPCHARP_STR(del),    del->len,    str->len,    del);    SET_ONERROR (uwp, do_free_object, mojt.container);       switch(str->size_shift)    {    case 0: f=(explode_searchfunc)mojt.vtab->func0; break;    case 1: f=(explode_searchfunc)mojt.vtab->func1; break;    case 2: f=(explode_searchfunc)mojt.vtab->func2; break; - #ifdef PIKE_DEBUG -  default: Pike_fatal("Illegal shift.\n"); - #endif +     }       while((tmp = f(mojt.data, s, (end-s)>> str->size_shift)))    {    if(ret->size == ret->malloced_size)    {    e=ret->size;    ACCEPT_UNFINISHED_TYPE_FIELDS {    ret=resize_array(ret, e * 2);    } END_ACCEPT_UNFINISHED_TYPE_FIELDS;
pike.git/src/array.c:2390:    * elements separated by a delimiter.    *    * @param a The array containing elements to be imploded    * @param del The delimiter used to separate the array's elements in the resulting string    * @return The imploded string    *    */   PMOD_EXPORT struct pike_string *implode(struct array *a,    struct pike_string *del)   { -  INT32 len, e; +  INT32 len, e, delims;    PCHARP r;    struct pike_string *ret;    struct svalue *ae;    int max_shift = del->size_shift;       len=0; -  +  delims = 0;    -  +  +     for(e=a->size, ae=a->item; e--; ae++)    switch(TYPEOF(*ae))    {    case T_INT:    if(!ae->u.integer)    continue; /* skip zero (strings) */    /* FALLTHROUGH */    default:    Pike_error("Array element %d is not a string\n", ae-a->item); -  +  break;    case T_STRING: -  +  delims++;    len+=ae->u.string->len + del->len;    if(ae->u.string->size_shift > max_shift)    max_shift=ae->u.string->size_shift;    break;    } -  if(len) len-=del->len; +     -  +  if(delims) +  { +  len-=del->len; +  delims--; +  } +  +  if( a->size == 1 && TYPEOF(*ITEM(a)) == PIKE_T_STRING ) +  { +  struct pike_string * res = ITEM(a)->u.string; +  res->refs++; +  return res; +  } +     ret=begin_wide_shared_string(len,max_shift);    r=MKPCHARP_STR(ret);    len = del->len;    if((e = a->size)) -  for(ae=a->item;;ae++) +  for(ae=a->item;e--;ae++)    { -  switch(TYPEOF(*ae)) +  if (TYPEOF(*ae) == T_STRING)    { -  case T_STRING: -  { +     struct pike_string *tmp = ae->u.string;    pike_string_cpy(r,tmp);    INC_PCHARP(r,tmp->len); -  break; -  } -  default: -  case T_INT: -  if(!--e) -  goto ret; -  continue; -  } -  if(!--e) -  break; -  if(len) +  if(len && delims)    { -  +  delims--;    pike_string_cpy(r,del);    INC_PCHARP(r,len);    }    } - ret: +  } +     return low_end_shared_string(ret);   }      /** Deeply copy an array. The mapping is used for temporary storage.    */   PMOD_EXPORT struct array *copy_array_recursively(struct array *a,    struct mapping *m)   {    struct array *ret;    struct svalue aa, bb;
pike.git/src/array.c:2499:   PMOD_EXPORT void apply_array(struct array *a, INT32 args, int flags)   {    INT32 e, hash = 0;    struct svalue *argp = Pike_sp-args;    struct array *cycl;    DECLARE_CYCLIC();       check_stack(args);    check_array_for_destruct(a);    for (e=0; e<args; e++) -  hash = hash * 33 + DO_NOT_WARN ((INT32) PTR_TO_INT (Pike_sp[-e-1].u.ptr)); +  hash = hash * 33 + (INT32) PTR_TO_INT (Pike_sp[-e-1].u.ptr);       if (!(cycl = (struct array *)BEGIN_CYCLIC(a, (ptrdiff_t)hash))) {    TYPE_FIELD new_types = 0; -  +  struct array *aa;    if ((flags & 1) && (a->refs == 1)) {    /* Destructive operation possible. */ -  ref_push_array(a); -  a->type_field |= BIT_UNFINISHED; +  add_ref(aa = a); +  aa->type_field |= BIT_UNFINISHED; +  } else { +  aa = allocate_array(a->size); +  } +  SET_CYCLIC_RET(aa); +  push_array(aa);    for (e=0; e < a->size; e++)    {    assign_svalues_no_free(Pike_sp, argp, args, BIT_MIXED);    Pike_sp+=args;    /* FIXME: Don't throw apply errors from apply_svalue here. */ -  apply_svalue(ITEM(a)+e,args); +  apply_svalue(ITEM(a)+e, args);    new_types |= 1 << TYPEOF(Pike_sp[-1]); -  assign_svalue(ITEM(a)+e, &Pike_sp[-1]); +  assign_svalue(ITEM(aa)+e, &Pike_sp[-1]);    pop_stack();    } -  a->type_field = new_types; - #ifdef PIKE_DEBUG -  array_check_type_field(a); - #endif -  } else { -  struct array *aa; -  push_array(aa = allocate_array_no_init(0, a->size)); -  for (e=0; (e<a->size) && (e < aa->malloced_size); e++) -  { -  assign_svalues_no_free(Pike_sp, argp, args, BIT_MIXED); -  Pike_sp+=args; -  /* FIXME: Don't throw apply errors from apply_svalue here. */ -  apply_svalue(ITEM(a)+e,args); -  new_types |= 1 << TYPEOF(Pike_sp[-1]); -  assign_svalue_no_free(ITEM(aa)+e, &Pike_sp[-1]); -  aa->size = e+1; -  pop_stack(); -  } +     aa->type_field = new_types;   #ifdef PIKE_DEBUG    array_check_type_field(aa);   #endif -  } +     stack_pop_n_elems_keep_top(args);    }    else {    pop_n_elems(args);    ref_push_array(cycl);    }       END_CYCLIC();   }   
pike.git/src/array.c:2610:      /** Replaces all from elements in array a with to elements. Called    * from replaces when first argument is an array. The replace is applied    * desctructivly.    */   void array_replace(struct array *a,    struct svalue *from,    struct svalue *to)   {    ptrdiff_t i = -1; -  -  while((i=array_search(a,from,i+1)) >= 0) array_set_index(a,i,to); +  check_array_for_destruct(a); +  while((i=fast_array_search(a,from,i+1)) >= 0) array_set_index(a,i,to);   }      #ifdef PIKE_DEBUG   PMOD_EXPORT void check_array(struct array *a)   {    INT32 e;       if(a->next && a->next->prev != a)    Pike_fatal("array->next->prev != array.\n");   
pike.git/src/array.c:2654: Inside #if defined(PIKE_DEBUG) and #if defined(DEBUG_MALLOC)
   {   #ifdef DEBUG_MALLOC    describe(a);   #endif    Pike_fatal("Array item pointer is too small!\n");    }       if(a->refs <=0 )    Pike_fatal("Array has zero refs.\n");    -  +     for(e=0;e<a->size;e++)    {    if(! ( (1 << TYPEOF(ITEM(a)[e])) & (a->type_field) ) &&    TYPEOF(ITEM(a)[e])<16)    Pike_fatal("Type field lies.\n");       check_svalue(ITEM(a)+e);    }   }      void check_all_arrays(void)   {    struct array *a;    for (a = first_array; a; a = a->next)    check_array(a);   }   #endif /* PIKE_DEBUG */       - PMOD_EXPORT void visit_array (struct array *a, int action) + PMOD_EXPORT void visit_array (struct array *a, int action, void *extra)   { -  switch (action) { +  visit_enter(a, T_ARRAY, extra); +  switch (action & VISIT_MODE_MASK) {   #ifdef PIKE_DEBUG    default:    Pike_fatal ("Unknown visit action %d.\n", action);    case VISIT_NORMAL:    case VISIT_COMPLEX_ONLY:    break;   #endif    case VISIT_COUNT_BYTES:    mc_counted_bytes += sizeof (struct array) +    (a->malloced_size - 1) * sizeof (struct svalue);    break;    }    -  if (a->type_field & +  if (!(action & VISIT_NO_REFS) && +  a->type_field &    (action & VISIT_COMPLEX_ONLY ? BIT_COMPLEX : BIT_REF_TYPES)) {    size_t e, s = a->size;    int ref_type = a->flags & ARRAY_WEAK_FLAG ? REF_TYPE_WEAK : REF_TYPE_NORMAL;    for (e = 0; e < s; e++) -  visit_svalue (ITEM (a) + e, ref_type); +  visit_svalue (ITEM (a) + e, ref_type, extra);    } -  +  visit_leave(a, T_ARRAY, extra);   }      static void gc_check_array(struct array *a)   {    GC_ENTER (a, T_ARRAY) {    if(a->type_field & BIT_COMPLEX)    {    if (a->flags & ARRAY_WEAK_FLAG) {    gc_check_weak_svalues(ITEM(a), a->size);    gc_checked_as_weak(a);