Branch: Tag:

2010-10-10

2010-10-10 21:56:19 by Martin Stjernholm <mast@lysator.liu.se>

Refactored the comparison functions a bit.

They now uses the same code to compare objects and functions: Objects
without any comparison lfuns are now compared according to their addresses,
to achieve a well defined internal order. Also, pointers to the same
function in different objects of the same program are now compared according
to their objects.

2:   || 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: array.c,v 1.229 2010/07/11 12:39:11 jonasw Exp $ + || $Id$   */      #include "global.h"
910:    return current_order;   }    - /* Returns 2 if no relation is established through lfun calls. */ - static INLINE int lfun_cmp (const struct svalue *a, const struct svalue *b) + /* Returns 2 if no relation is established through lfun calls, or 3 if +  * no order defining lfuns (i.e. `< or `>) were found. */ + static int lfun_cmp (const struct svalue *a, const struct svalue *b)   {    struct program *p; -  int fun; +  int default_res = 3, fun;       if (a->type == T_OBJECT && (p = a->u.object->prog)) {    if ((fun = FIND_LFUN(p->inherits[a->subtype].prog, LFUN_LT)) != -1) {
927:    return -1;    }    pop_stack(); +  default_res = 2;    }       if ((fun = FIND_LFUN(p->inherits[a->subtype].prog, LFUN_GT)) != -1) {
939:    return 1;    }    pop_stack(); +  default_res = 2;    }       if ((fun = FIND_LFUN(p->inherits[a->subtype].prog, LFUN_EQ)) != -1) {
964:    return 1;    }    pop_stack(); +  default_res = 2;    }       if ((fun = FIND_LFUN(p->inherits[b->subtype].prog, LFUN_GT)) != -1) {
976:    return -1;    }    pop_stack(); +  default_res = 2;    }       if ((fun = FIND_LFUN(p->inherits[b->subtype].prog, LFUN_EQ)) != -1) {
990:    }    }    -  return 2; +  return default_res;   }    - int set_svalue_cmpfun(const struct svalue *a, const struct svalue *b) + static int obj_or_func_cmp (const struct svalue *a, const struct svalue *b) + /* Call with either two T_OBJECT or two T_FUNCTION. */   { -  int res, typediff = a->type - b->type; +  int a_subtype, b_subtype, res; +  struct svalue tmp_a, tmp_b;    -  if (!typediff) +  assert ((a->type == T_OBJECT && b->type == T_OBJECT) || +  (a->type == T_FUNCTION && b->type == T_FUNCTION)); +  +  if (a->u.object == b->u.object) +  return a->subtype - b->subtype; +  +  /* Destructed objects are considered equal to each other, and +  * (arbitrarily chosen) greater than others. */ +  if (!a->u.object->prog) +  return !b->u.object->prog ? 0 : 1; +  else if (!b->u.object->prog) +  return -1; +  +  if (a->type == T_FUNCTION) { +  if (a->u.object->prog != b->u.object->prog) +  return a->u.object->prog < b->u.object->prog ? -1 : 1; +  if (a->subtype != b->subtype) +  return a->subtype - b->subtype; +  +  /* We have the same function but in different objects. Compare the +  * objects themselves. */ +  /* FIXME: Should we try to convert the subtypes to the ones for +  * the closest inherits? That'd make some sense if the functions +  * are private, but otherwise it's doubtful. */ +  a_subtype = b_subtype = a->subtype; +  tmp_a = *a; +  tmp_a.type = T_OBJECT; +  tmp_a.subtype = 0; +  a = &tmp_a; +  tmp_b = *b; +  tmp_b.type = T_OBJECT; +  tmp_b.subtype = 0; +  b = &tmp_b; +  } +  +  else { +  a_subtype = a->subtype; +  b_subtype = b->subtype; +  } +  +  res = lfun_cmp (a, b); +  +  if (res == 3) { +  /* If the objects had no inequality comparison lfuns to call, use +  * their pointers to get a well defined internal sort order. Let's +  * also group objects cloned from the same program. */ +  if (a->u.object->prog == b->u.object->prog) +  return a->u.object < b->u.object ? -1 : 1; +  else +  return a->u.object->prog < b->u.object->prog ? -1 : 1; +  } +  +  return res == 2 ? 0 : res; + } +  + int set_svalue_cmpfun(const struct svalue *a, const struct svalue *b)   { -  +  int typediff = a->type - b->type; +  if (typediff) { +  if (a->type == T_OBJECT || b->type == T_OBJECT) { +  int res = lfun_cmp (a, b); +  if (res < 2) return res; +  } +  return typediff; +  } +     switch(a->type)    {    case T_FLOAT:
1006:    if(a->u.float_number > b->u.float_number) return 1;    return 0;    -  case T_FUNCTION: -  if(a->u.refs < b->u.refs) return -1; -  if(a->u.refs > b->u.refs) return 1; -  return a->subtype - b->subtype; -  +     case T_INT:    if(a->u.integer < b->u.integer) return -1;    if(a->u.integer > b->u.integer) return 1;    return 0;    -  +  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; -  -  case T_OBJECT: -  if((a->u.object == b->u.object) && (a->subtype == b->subtype)) { -  return 0; +     } -  break; +  /* NOT REACHED */   } -  } +     -  res = lfun_cmp (a, b); -  if (res != 2) return res; -  -  if (typediff) return typediff; -  - #ifdef PIKE_DEBUG -  if (a->type != T_OBJECT) -  Pike_fatal ("Expected objects when both types are the same.\n"); - #endif -  -  /* FIXME: Take subtype into account! */ -  -  if(a->u.object->prog == b->u.object->prog) { -  if (a->u.object->prog) { -  if(a->u.object < b->u.object) { -  return -1; -  } else { -  return 1; -  } -  } else { -  /* Destructed objects are considered equal. */ -  return 0; -  } -  } else { -  /* Attempt to group objects cloned from the same program */ -  if (a->u.object->prog < b->u.object->prog) { -  return -1; -  } else { -  return 1; -  } -  } - } -  +    static int switch_svalue_cmpfun(const struct svalue *a, const struct svalue *b)   { -  if(a->type == b->type) -  { +  int typediff = a->type - b->type; +  if (typediff) +  return typediff; +     switch(a->type)    {    case T_INT:
1081:    case T_STRING:    return DO_NOT_WARN((int)my_quick_strcmp(a->u.string, b->u.string));    +  case T_OBJECT: +  case T_FUNCTION: +  return obj_or_func_cmp (a, b); +     default: -  return set_svalue_cmpfun(a,b); +  if(a->u.refs < b->u.refs) return -1; +  if(a->u.refs > b->u.refs) return 1; +  return 0;    } -  }else{ -  return a->type - b->type; +  /* NOT REACHED */   } - } +       int alpha_svalue_cmpfun(const struct svalue *a, const struct svalue *b)   { -  int res, typediff = a->type - b->type; +  int typediff = a->type - b->type; +  if (typediff) { +  if (a->type == T_OBJECT || b->type == T_OBJECT) { +  int res = lfun_cmp (a, b); +  if (res < 2) return res; +  } +  return typediff; +  }    -  if (!typediff) -  { +     switch(a->type)    {    case T_INT:
1127:    {    ptrdiff_t a_pos = multiset_first (a->u.multiset);    ptrdiff_t b_pos = multiset_first (b->u.multiset); +  int res;    struct svalue ind_a, ind_b;    if (a_pos < 0)    if (b_pos < 0)
1145:    }       case T_OBJECT: -  if((a->u.object == b->u.object) && (a->subtype == b->subtype)) { -  return 0; -  } -  break; +  case T_FUNCTION: +  return obj_or_func_cmp (a, b);       default: - #if 1 -  /* I think it would be better to leave the order undefined in -  * these cases since the addresses aren't observable -  * properties in pike. /mast */ -  if(a->u.refs < b->u.refs) return -1; -  if(a->u.refs > b->u.refs) return 1; - #endif +  if(a->u.ptr < b->u.ptr) return -1; +  if(a->u.ptr > b->u.ptr) return 1;    return 0;    } -  +  /* NOT REACHED */   }    -  res = lfun_cmp (a, b); -  if (res != 2) return res; -  -  return typediff; - } -  +    #define CMP(X,Y) alpha_svalue_cmpfun(X,Y)   #define TYPE struct svalue   #define ID low_sort_svalues