#pike __REAL_VERSION__ |
|
#pragma strict_types |
|
constant diff = __builtin.diff; |
constant diff_longest_sequence = __builtin.diff_longest_sequence; |
constant diff_compare_table = __builtin.diff_compare_table; |
constant longest_ordered_sequence = __builtin.longest_ordered_sequence; |
constant interleave_array = __builtin.interleave_array; |
|
constant sort = predef::sort; |
constant everynth = __builtin.everynth; |
constant splice = __builtin.splice; |
constant transpose = __builtin.transpose; |
constant uniq = __builtin.uniq_array; |
|
constant filter=predef::filter; |
constant map=predef::map; |
constant permute = __builtin.permute; |
constant enumerate = predef::enumerate; |
constant Iterator = __builtin.array_iterator; |
|
|
|
|
|
|
|
|
|
|
mixed reduce(function fun, array arr, mixed|void zero) |
{ |
if(sizeof(arr)) |
zero = arr[0]; |
for(int i=1; i<sizeof(arr); i++) |
zero = ([function(mixed,mixed:mixed)]fun)(zero, arr[i]); |
return zero; |
} |
|
|
|
|
|
|
|
|
|
|
mixed rreduce(function fun, array arr, mixed|void zero) |
{ |
if(sizeof(arr)) |
zero = arr[-1]; |
for(int i=sizeof(arr)-2; i>=0; --i) |
zero = ([function(mixed,mixed:mixed)]fun)(arr[i], zero); |
return zero; |
} |
|
|
|
|
|
|
|
array shuffle(array arr) |
{ |
int i = sizeof(arr); |
|
while(i) { |
int j = random(i--); |
if (j != i) { |
mixed tmp = arr[i]; |
arr[i] = arr[j]; |
arr[j] = tmp; |
} |
} |
return(arr); |
} |
|
|
|
|
|
|
|
|
|
int search_array(array arr, string|function|int fun, mixed ... args) |
{ |
int e; |
|
if(stringp(fun)) |
{ |
for(e=0;e<sizeof(arr);e++) |
if(([function(mixed...:mixed)]([array(object)]arr)[e][fun])(@args)) |
return e; |
return -1; |
} |
else if(functionp(fun)) |
{ |
for(e=0;e<sizeof(arr);e++) |
if(([function(mixed,mixed...:mixed)]fun)(arr[e],@args)) |
return e; |
return -1; |
} |
else if(intp(fun)) |
{ |
for(e=0;e<sizeof(arr);e++) |
if(([array(function(mixed...:mixed))]arr)[e](@args)) |
return e; |
return -1; |
} |
|
error("Bad argument 2 to search_array().\n"); |
} |
|
|
|
|
array sum_arrays(function(mixed ...:mixed) sum, array ... args) |
{ |
array ret = allocate(sizeof(args[0])); |
for(int e=0; e<sizeof(args[0]); e++) |
ret[e] = sum( @column(args, e) ); |
return ret; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
array sort_array(array foo, function|void cmp, mixed ... args) |
{ |
array bar,tmp; |
int len,start; |
int length; |
int foop, fooend, barp, barend; |
|
if(!cmp || cmp==`>) |
{ |
foo+=({}); |
sort(foo); |
return foo; |
} |
|
if(cmp == `<) |
{ |
foo+=({}); |
sort(foo); |
return reverse(foo); |
} |
|
length=sizeof(foo); |
|
foo+=({}); |
bar=allocate(length); |
|
for(len=1;len<length;len*=2) |
{ |
start=0; |
while(start+len < length) |
{ |
foop=start; |
barp=start+len; |
fooend=barp; |
barend=barp+len; |
if(barend > length) barend=length; |
|
while(1) |
{ |
if(([function(mixed,mixed,mixed...:int)]cmp)(foo[foop],foo[barp],@args) |
<= 0) |
{ |
bar[start++]=foo[foop++]; |
if(foop == fooend) |
{ |
while(barp < barend) bar[start++]=foo[barp++]; |
break; |
} |
}else{ |
bar[start++]=foo[barp++]; |
if(barp == barend) |
{ |
while(foop < fooend) bar[start++]=foo[foop++]; |
break; |
} |
} |
} |
} |
while(start < length) bar[start]=foo[start++]; |
|
tmp=foo; |
foo=bar; |
bar=tmp; |
} |
|
return foo; |
} |
|
array columns(array x, array ind) |
{ |
array ret=allocate(sizeof(ind)); |
for(int e=0;e<sizeof(ind);e++) ret[e]=column(x,ind[e]); |
return ret; |
} |
|
array transpose_old(array(array|string) x) |
{ |
if (!sizeof(x)) return x; |
array ret=allocate(sizeof([array|string]x[0])); |
for(int e=0;e<sizeof([array|string]x[0]);e++) ret[e]=column(x,e); |
return ret; |
} |
|
|
|
array(array(array)) diff3 (array a, array b, array c) |
{ |
|
|
|
array(int) seq_ab = diff_longest_sequence (a, b); |
array(int) seq_bc = diff_longest_sequence (b, c); |
array(int) seq_ca = diff_longest_sequence (c, a); |
|
array(int) aeq = allocate (sizeof (a) + 1); |
array(int) beq = allocate (sizeof (b) + 1); |
array(int) ceq = allocate (sizeof (c) + 1); |
aeq[sizeof (a)] = beq[sizeof (b)] = ceq[sizeof (c)] = 7; |
|
for (int i = 0, j = 0; j < sizeof (seq_ab); i++) |
if (a[i] == b[seq_ab[j]]) aeq[i] |= 2, beq[seq_ab[j]] |= 1, j++; |
for (int i = 0, j = 0; j < sizeof (seq_bc); i++) |
if (b[i] == c[seq_bc[j]]) beq[i] |= 2, ceq[seq_bc[j]] |= 1, j++; |
for (int i = 0, j = 0; j < sizeof (seq_ca); i++) |
if (c[i] == a[seq_ca[j]]) ceq[i] |= 2, aeq[seq_ca[j]] |= 1, j++; |
|
|
|
array(array) ares = ({}), bres = ({}), cres = ({}); |
int ai = 0, bi = 0, ci = 0; |
int prevodd = -2; |
|
while (!(aeq[ai] & beq[bi] & ceq[ci] & 4)) { |
|
|
array empty = ({}), apart = empty, bpart = empty, cpart = empty; |
int side = aeq[ai] & beq[bi] & ceq[ci]; |
|
if ((<1, 2>)[side]) { |
|
|
int which, merge, inv_side = side ^ 3, i, oi; |
array(int) eq, oeq; |
array arr, oarr; |
int atest = side == 1 ? ceq[ci] != 3 : beq[bi] != 3; |
int btest = side == 1 ? aeq[ai] != 3 : ceq[ci] != 3; |
int ctest = side == 1 ? beq[bi] != 3 : aeq[ai] != 3; |
|
for (i = 0;; i++) { |
int abreak = atest && aeq[ai] != aeq[ai + i]; |
int bbreak = btest && beq[bi] != beq[bi + i]; |
int cbreak = ctest && ceq[ci] != ceq[ci + i]; |
|
if (abreak + bbreak + cbreak > 1) { |
|
|
if (side == 1) { |
if (!atest) cbreak = 0; |
if (!btest) abreak = 0; |
if (!ctest) bbreak = 0; |
} |
else { |
if (!atest) bbreak = 0; |
if (!btest) cbreak = 0; |
if (!ctest) abreak = 0; |
} |
|
|
switch (prevodd) { |
case 0: if (abreak) bbreak = cbreak = 0; break; |
case 1: if (bbreak) cbreak = abreak = 0; break; |
case 2: if (cbreak) abreak = bbreak = 0; break; |
} |
} |
|
if (abreak) { |
which = 0, merge = (<0, -1>)[prevodd]; |
i = ai, eq = aeq, arr = a; |
if (inv_side == 1) oi = bi, oeq = beq, oarr = b; |
else oi = ci, oeq = ceq, oarr = c; |
break; |
} |
if (bbreak) { |
which = 1, merge = (<1, -1>)[prevodd]; |
i = bi, eq = beq, arr = b; |
if (inv_side == 1) oi = ci, oeq = ceq, oarr = c; |
else oi = ai, oeq = aeq, oarr = a; |
break; |
} |
if (cbreak) { |
which = 2, merge = (<2, -1>)[prevodd]; |
i = ci, eq = ceq, arr = c; |
if (inv_side == 1) oi = ai, oeq = aeq, oarr = a; |
else oi = bi, oeq = beq, oarr = b; |
break; |
} |
} |
|
|
|
int s = i, mask = eq[i]; |
do { |
eq[i++] &= inv_side; |
while (!(oeq[oi] & inv_side)) oi++; |
oeq[oi] &= side; |
} |
while (eq[i] == mask); |
|
if (merge && !eq[s]) { |
array part = ({}); |
do part += ({arr[s++]}); while (!eq[s]); |
switch (which) { |
case 0: ai = s; ares[-1] += part; break; |
case 1: bi = s; bres[-1] += part; break; |
case 2: ci = s; cres[-1] += part; break; |
} |
} |
} |
|
|
|
if (aeq[ai] == 2 && beq[bi] == 1) { |
do apart += ({a[ai++]}), bi++; while (aeq[ai] == 2 && beq[bi] == 1); |
bpart = apart; |
while (!ceq[ci]) cpart += ({c[ci++]}); |
prevodd = 2; |
} |
else if (beq[bi] == 2 && ceq[ci] == 1) { |
do bpart += ({b[bi++]}), ci++; while (beq[bi] == 2 && ceq[ci] == 1); |
cpart = bpart; |
while (!aeq[ai]) apart += ({a[ai++]}); |
prevodd = 0; |
} |
else if (ceq[ci] == 2 && aeq[ai] == 1) { |
do cpart += ({c[ci++]}), ai++; while (ceq[ci] == 2 && aeq[ai] == 1); |
apart = cpart; |
while (!beq[bi]) bpart += ({b[bi++]}); |
prevodd = 1; |
} |
|
else if ((<1*2*3, 3*3*3>)[aeq[ai] * beq[bi] * ceq[ci]]) { |
|
|
|
do apart += ({a[ai++]}), bi++, ci++; |
while ((<0333, 0123, 0312, 0231>)[aeq[ai] << 6 | beq[bi] << 3 | ceq[ci]]); |
cpart = bpart = apart; |
prevodd = -1; |
} |
|
else { |
|
|
|
|
switch (prevodd) { |
case 0: apart = ares[-1], ares[-1] = ({}); break; |
case 1: bpart = bres[-1], bres[-1] = ({}); break; |
case 2: cpart = cres[-1], cres[-1] = ({}); break; |
} |
prevodd = -1; |
while (!aeq[ai]) apart += ({a[ai++]}); |
while (!beq[bi]) bpart += ({b[bi++]}); |
while (!ceq[ci]) cpart += ({c[ci++]}); |
} |
|
|
ares += ({apart}), bres += ({bpart}), cres += ({cpart}); |
} |
|
return ({ares, bres, cres}); |
} |
|
|
|
array(array(array)) diff3_old(array mid,array left,array right) |
{ |
array(array) lmid,ldst; |
array(array) rmid,rdst; |
|
[lmid,ldst]=diff(mid,left); |
[rmid,rdst]=diff(mid,right); |
|
int l=0,r=0,n; |
array(array(array)) res=({}); |
int lpos=0,rpos=0; |
array eq=({}); |
int x; |
|
for (n=0; ;) |
{ |
while (l<sizeof(lmid) && lpos>=sizeof(lmid[l])) |
{ |
if (sizeof(ldst[l])>lpos) |
res+=({({({}),ldst[l][lpos..],({})})}); |
l++; |
lpos=0; |
} |
while (r<sizeof(rmid) && rpos>=sizeof(rmid[r])) |
{ |
if (sizeof(rdst[r])>rpos) |
res+=({({({}),({}),rdst[r][rpos..]})}); |
r++; |
rpos=0; |
} |
|
if (n==sizeof(mid)) break; |
|
x=min(sizeof(lmid[l])-lpos,sizeof(rmid[r])-rpos); |
|
if (lmid[l]==ldst[l] && rmid[r]==rdst[r]) |
{ |
eq=lmid[l][lpos..lpos+x-1]; |
res+=({({eq,eq,eq})}); |
} |
else if (lmid[l]==ldst[l]) |
{ |
eq=lmid[l][lpos..lpos+x-1]; |
res+=({({eq,eq,rdst[r][rpos..rpos+x-1]})}); |
} |
else if (rmid[r]==rdst[r]) |
{ |
eq=rmid[r][rpos..rpos+x-1]; |
res+=({({eq,ldst[l][lpos..lpos+x-1],eq})}); |
} |
else |
{ |
res+=({({lmid[l][lpos..lpos+x-1], |
ldst[l][lpos..lpos+x-1], |
rdst[r][rpos..rpos+x-1]})}); |
} |
|
|
|
|
rpos+=x; |
lpos+=x; |
n+=x; |
} |
|
return transpose(res); |
} |
|
|
|
int(-1..1) dwim_sort_func(string a, string b) |
{ |
if (a==b) return 0; |
array aa=({}), bb=({}); |
int state, oi; |
|
for( int i = 0; i<sizeof(a); i++ ) |
if( (<'0','1','2','3','4','5','6','7','8','9'>)[a[i]] != state ) |
{ |
state = !state; |
if( state ) |
aa += ({ a[oi..i-1] }); |
else |
aa += ({ (int)a[oi..i-1] }); |
oi = i; |
} |
if( state ) |
aa += ({ (int)a[oi..] }); |
else |
aa += ({ a[oi..] }); |
|
|
oi = state = 0; |
|
for( int i = 0; i<sizeof(b); i++ ) |
if( (<'0','1','2','3','4','5','6','7','8','9'>)[b[i]] != state ) |
{ |
state = !state; |
if( state ) |
bb += ({ b[oi..i-1] }); |
else |
bb += ({ (int)b[oi..i-1] }); |
oi = i; |
} |
if( state ) |
bb += ({ (int)b[oi..] }); |
else |
bb += ({ b[oi..] }); |
|
for( int i = 0; i<sizeof( aa ); i++ ) |
{ |
if( i >= sizeof( bb ) ) return 1; |
|
if( aa[i] < bb[i] ) return -1; |
if( aa[i] > bb[i] ) return 1; |
} |
|
|
|
return [int(-1..1)]-(sizeof(aa)<sizeof(bb)); |
} |
|
|
|
|
|
int(-1..1) lyskom_sort_func(string a,string b) |
{ |
string a0=a,b0=b; |
a=replace(lower_case(a),"][\\}{|"/1,"åäöåäö"/1); |
b=replace(lower_case(b),"][\\}{|"/1,"åäöåäö"/1); |
|
while (sscanf(a0=a,"%*[ \t](%*[^)])%*[ \t]%s",a)==4 && a0!=a); |
while (sscanf(b0=b,"%*[ \t](%*[^)])%*[ \t]%s",b)==4 && b0!=b); |
a0=b0=""; |
sscanf(a,"%[^ \t]%*[ \t](%*[^)])%*[ \t]%s",a,a0); |
sscanf(b,"%[^ \t]%*[ \t](%*[^)])%*[ \t]%s",b,b0); |
if (a>b) return 1; |
if (a<b) return -1; |
if (a0==b0) return 0; |
return lyskom_sort_func(a0,b0); |
} |
|
|
|
|
|
array flatten(array a, mapping(array:array)|void state) |
{ |
if (state && state[a]) return state[a]; |
if (!state) state = ([a:({})]); |
else state[a] = ({}); |
array res = allocate(sizeof(a)); |
foreach(a; int i; mixed b) { |
res[i] = arrayp(b)?flatten([array]b, state):({b}); |
} |
return state[a] = (res*({})); |
} |
|
|
|
mixed sum(array a) |
{ |
if(a==({})) return 0; |
|
if (sizeof(a)<1000) |
return `+(@a); |
else |
{ |
mixed mem=`+(@a[..999]); |
int j=1000; |
array v; |
while (sizeof(v=a[j..j+999])) |
mem=`+(mem,@v),j+=1000; |
return mem; |
} |
} |
|
|
|
|
|
|
|
|
array uniq2(array a) |
{ |
array res; |
mixed last; |
if (!sizeof(a)) return ({}); |
res=({last=a[0]}); |
foreach (a,mixed v) |
if (v!=last) last=v,res+=({v}); |
return res; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
array arrayify(void|array|mixed x) |
{ |
if(zero_type(x)) return ({}); |
if(arrayp(x)) return [array]x; |
return ({ x }); |
} |
|
|
|
|
|
int oid_sort_func(string a0,string b0) |
{ |
string a2="",b2=""; |
int a1, b1; |
sscanf(a0,"%d.%s",a1,a2); |
sscanf(b0,"%d.%s",b1,b2); |
if (a1>b1) return 1; |
if (a1<b1) return 0; |
if (a2==b2) return 0; |
return oid_sort_func(a2,b2); |
} |
|
static array(array(array)) low_greedy_diff(array(array) d1, array(array) d2) |
{ |
array r1, r2, x, y, yb, b, c; |
r1 = r2 = ({}); |
int at, last, seen; |
while(-1 != (at = search(d1, ({}), last))) |
{ |
last = at + 1; |
if(at < 2) continue; |
b = d2[at-1]; yb = d2[at]; |
out:if(sizeof(yb) > sizeof(b)) |
{ |
int i = sizeof(b), j = sizeof(yb); |
while(i) |
if(b[--i] != yb[--j]) |
break out; |
x = d2[at-2]; |
y = yb[..sizeof(yb)-sizeof(b)-1]; |
if(at+1 <= sizeof(d1)) |
{ |
c = d2[at+1]; |
array bc = b+c; |
r1 += d1[seen..at-2] + ({ bc }); |
r2 += d2[seen..at-3] + ({ x+b+y }) + ({ bc }); |
} |
else |
{ |
|
r1 += d1[seen..at-2] + ({ b }); |
r2 += d2[seen..at-3] + ({ x+b+y }) + ({ b }); |
} |
seen = at + 5; |
} |
} |
if(!seen) |
return ({ d1, d2 }); |
return ({ [array(array)]r1 + d1[seen..], |
[array(array)]r2 + d2[seen..] }); |
} |
|
|
|
|
|
|
|
|
|
array(array(array)) greedy_diff(array from, array to) |
{ |
array(array) d1, d2; |
[d1, d2] = diff(from, to); |
[d2, d1] = low_greedy_diff(d2, d1); |
return low_greedy_diff(d1, d2); |
} |
|
|
|
|
|
|
|
|
|
|
|
int|mapping(mixed:int) count(array|mapping|multiset haystack, |
mixed|void needle) |
{ |
if(zero_type(needle)) |
{ |
mapping(mixed:int) res = ([]); |
if(mappingp(haystack)) |
haystack = values([mapping]haystack); |
foreach((array)haystack, mixed what) |
res[what]++; |
return res; |
} |
return sizeof(filter(haystack, `==, needle)); |
} |
|
|
|
|
array common_prefix(array(array) arrs) |
{ |
if(!sizeof(arrs)) |
return ({}); |
|
array arrs0 = arrs[0]; |
int n, i; |
|
catch |
{ |
for(n = 0; n < sizeof(arrs0); n++) |
for(i = 1; i < sizeof(arrs); i++) |
if(!equal(arrs[i][n],arrs0[n])) |
return arrs0[0..n-1]; |
}; |
|
return arrs0[0..n-1]; |
} |
|
|