/*
* 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;
}