MudOSa4DGD/
MudOSa4DGD/bin/
MudOSa4DGD/data/
MudOSa4DGD/doc/
MudOSa4DGD/doc/driver/
MudOSa4DGD/doc/efun/bitstrings/
MudOSa4DGD/doc/efun/command/
MudOSa4DGD/doc/efun/communication/
MudOSa4DGD/doc/efun/heart_beat/
MudOSa4DGD/doc/efun/interactive/
MudOSa4DGD/doc/efun/inventory/
MudOSa4DGD/doc/efun/living/
MudOSa4DGD/doc/efun/mappings/
MudOSa4DGD/doc/efun/strings/
MudOSa4DGD/doc/efun/uid/
MudOSa4DGD/doc/funs/
MudOSa4DGD/doc/language/
MudOSa4DGD/mudlib/dgd/doc/
MudOSa4DGD/mudlib/dgd/lib/include/dgd/
MudOSa4DGD/mudlib/dgd/lib/std/
MudOSa4DGD/mudlib/dgd/lib/sys/
MudOSa4DGD/mudlib/dgd/log/
MudOSa4DGD/mudlib/log/
MudOSa4DGD/mudlib/std/include/
MudOSa4DGD/mudlib/std/obj/
/*
 * array.c
 *
 * Some handy array functions
 *
 * (C) Frank Schmidt, Jesus@NorseMUD
 *
 */


#ifndef a_sizeof
/* do array based sizeof */
static int a_sizeof(mixed *arr) {
  return ::sizeof(arr);
}
#endif


#ifndef array_delete
/* delete an element in an array (NB! Array <arr> not changed) */
static mixed *array_delete(mixed *arr, int e) {
  return arr = arr[..e-1] + arr[e+1..];
}
#endif



/* extract a subarray from an array,  
   accepts negative values and out of bounds 
*/ 
static mixed *extract_array(mixed *arr, int from, int to) { 
  int sz;
  sz = ::sizeof(arr);
  if (to < 0)
    to = sz+to;
  else if (to >= sz)
    to = sz-1;
  if (to < from || from >= sz)
    return ({ });
  if (from <= 0) return arr[..to];
  return arr[from..to];
}


/* nifty function that returns all but the part you specify,
   accepts negative values and out of bounds
*/
static mixed *exclude_array(mixed *arr, int from, int to) {
  mixed *fore;
  int sz;
  sz = ::sizeof(arr);
  if (to < 0)
    to = sz+to;
  else if (to >= sz)
    to = sz-1;
  if (to < from || from >= sz)
    return arr;
  if (from > 0)
    fore = arr[..from-1];
  else
    fore = ({ });
  if (to >= sz-1) return fore;
  return fore + arr[to+1..];
}


/* inserts array into an array safely,
   accepts out of bounds values
*/
static mixed *insert_array(mixed *arr, mixed what, int where) {
  if (!arrayp(what))
    what = ({ what });
  if (where <= 0)
    return what + arr;
  if (where >= ::sizeof(arr))
    return arr + what;
  return arr[..where-1] + what + arr[where..];
}



#ifdef MUDOS_MEMBER_ARRAY_FLAG

/* return first index of the element in the array, or -1 */
static varargs int member_array(mixed elt, mixed *arr, int flag) {
  int i, sz;
  if (!flag) {
    for (sz = ::sizeof(arr); i<sz; ++i) {
      if (arr[i] == elt)
	return i;
    }
  }
  else {
    int eltlen;
    eltlen = strlen((string)elt);
    for (sz = ::sizeof(arr); i<sz; ++i) {
      if (arr[i][..eltlen-1] == elt)
	return i;
    }
  }
  return -1;
}

#else

/* return index of the <n>th element in the array, or -1 */
static varargs int member_array(mixed elt, mixed *arr, int n) {
  int i;
  if (n >= 0) {
    int sz;
    for (sz = ::sizeof(arr); i<sz; ++i) {
      if (arr[i] == elt && --n < 0)
	return i;
    }
  }
  else {
    for (i = ::sizeof(arr); --i >= 0; ) {
      if (arr[i] == elt && ++n >= 0)
	return i;
    }
  }
  return -1;
}

#endif /* MUDOS_MEMBER_ARRAY_FLAG */



/* filter away elements in an array, get values from ob->fun(element) */
static varargs mixed *filter_array(mixed *arr, string fun, mixed ob, mixed args...) {
  int i, sz;
  mixed *result, el;
  result = ({ });
  for (sz = ::sizeof(arr); i < sz; ++i) {
    if (__call_other(ob, fun, (el=arr[i]), args...))
      result += ({ el });
  }
  return result;
}


/* map elements in an array */
static varargs mixed *map_array(mixed *arr, string fun, mixed ob, mixed args...) {
  int i, sz;
  mixed *result;
  result = allocate(sz = ::sizeof(arr));
  for (; i < sz; ++i)
    result[i] = (__call_other(ob, fun, arr[i], args...));
  return result;
}


/* sort an array. Currently using fast version of bubble-sort (with inner loop) */
static varargs mixed *sort_array(mixed *arr, mixed fun, mixed ob, int dir) {
  int i, e, sz;
  mixed *sarr, a, b, a2;

  if (!stringp(fun)) {
    /* 0-size? */
    if (!::sizeof(arr))
      return arr;
    /* check for pre-defined sort_array types */
    switch (typeof(arr[0])) {
    case T_STRING:
      return sort_array(arr, "sort_alpha_asc", GLOBAL, dir);
    case T_INT:
      return sort_array(arr, "sort_num_asc", GLOBAL, dir);
    case T_FLOAT:
      return sort_array(arr, "sort_float_asc", GLOBAL, dir);
    default:
      return copy(arr);
    }
  }

  /* ensure unique array to alter */
  sarr = copy(arr);
  i = ::sizeof(sarr);
  a = sarr[sz = --i];

  if (dir >= 0) {
    /* Ascending order. */
    while (--i >= 0) {
      b = sarr[i];
      if (__call_other(ob, fun, a, b) >= 0) {
	/* continue */
	a = b;
      }
      else {
	sarr[i] = a;
	e = i+1;
	while (__call_other(ob, fun, a2=sarr[e+1], b) < 0) {
	  /* swap backwards until we got it right */
	  sarr[e] = a2;
	  if (++e >= sz) break;
	}
	sarr[e] = b;
      }
    }
  }
  else {
    /* Descending order. */
    while (--i >= 0) {
      b = sarr[i];
      if (__call_other(ob, fun, a, b) > 0) {
	sarr[i] = a;
	e = i+1;
	while (__call_other(ob, fun, a2=sarr[e+1], b) > 0) {
	  /* swap backwards until we got it right */
	  sarr[e] = a2;
	  if (++e >= sz) break;
	}
	sarr[e] = b;
      }
      else {
	/* continue */
	a = b;
      }
    }
  }
  return sarr;
}


#if 0
/* subdivide an array of objects into arrays with objects where
 * obj->func() returned identical descriptions
 */
static varargs mixed *unique_array(mixed *arr, string func, mixed exclude, mixed args...) {
  mapping map;
  int i, sz;
  mixed val, elt;
  object *list;
  
  map = ([ ]);
  for (i = 0, sz = ::sizeof(arr); i < sz; i++) {
    elt = arr[i];
    if (objectp(elt) && (val=__call_other(elt, func, args...)) != exclude) {
      list = map[val];
      if (list == 0) {
	list = ({ elt });
      } else {
	list = ({ elt }) + list;
      }
      map[val] = list;
    }
  }
  return map_values(map);
}
#endif


/* return a flat array given a nested array */
static mixed *flatten_array(mixed *arr) {
  mixed *new_arr, elt;
  int i, sz;

  new_arr = ({ });
  for (i = 0, sz = ::sizeof(arr); i < sz; ++i) {
    if (arrayp(elt=arr[i]))
      new_arr += flatten_array(elt);
    else
      new_arr += ({ elt });
  }
  return new_arr;
}