/* Do not remove the headers from this file! see /USAGE for more info. */ /* For keeping track of sets of numbers. See also the set_bit()/test_bit() * series of efuns. The major advantage of this package is that the * storage requirements are much lower for sets with many consecutive * numbers, or for numbers which are sparsely distributed over a large * range. It isn't particularly efficient speedwise, but it is compact. * * The format is: x-x,y-z ... */ /* This function ensures that the sets aren't currupted. It returns 1 * if the set is valid and 0 on failure. * There may need to be more work done here -- Tigran */ int valid_set(string set) { int part1, part2; string rest; string array parts=explode(set,","); if(set="") return 1; foreach(string part in parts) { if(sscanf("%d-%d%s",part1,part2,rest)!=2) return 0; } return 1; } string set_add(string set, int number) { int idx, nextidx; int lastidx, lastfirst, lastlast = -10; if(!valid_set(set)) error(sprintf("Invalid set in set_add: %s\n",set)); if (set == "") return number + "-" + number; /* The cases we have to consider: 1-2 -> 1-2,4-4 1-2,4-5 -> 1-2,4-6 1-3,5-7 -> 1-7 */ idx = 0; do { string part; int first, last; nextidx = member_array(',', set, idx) + 1; if (!nextidx) part = set[idx..]; else part = set[idx..nextidx-2]; sscanf(part, "%d-%d", first, last); if (number < first) { string res; if (number == lastlast + 1) { if (number == first - 1) { res = set[0..lastidx-1] + lastfirst + "-" + last; if (nextidx) res += set[nextidx-1..]; return res; } return set[0..lastidx-1] + lastfirst + "-" + number + set[idx-1..]; } if (number == first - 1) { res = set[0..idx-1] + number + "-" + last; if (nextidx) res += set[nextidx-1..]; return res; } return set[0..idx-1] + number + "-" + number + "," + set[idx..]; } if (number <= last) return set; lastidx = idx; lastfirst = first; lastlast = last; idx = nextidx; } while (idx); if (number == lastlast + 1) return set[0..lastidx-1] + lastfirst + "-" + number; else return set + "," + number + "-" + number; } string set_add_range(string set, int nfirst, int nlast) { int idx, nextidx; int lastidx, lastfirst, lastlast = -10; if(!valid_set(set)) error(sprintf("Invalid set in set_add_range: %s\n",set)); if (set == "") return nfirst + "-" + nlast; idx = 0; do { string part; int first, last; nextidx = member_array(',', set, idx) + 1; if (!nextidx) part = set[idx..]; else part = set[idx..nextidx-2]; sscanf(part, "%d-%d", first, last); if (nfirst < first) { string res; int sidx; sidx = idx; while (nextidx && nlast > last) { idx = nextidx; nextidx = member_array(',', set, idx) + 1; if (!nextidx) part = set[idx..]; else part = set[idx..nextidx-2]; sscanf(part, "%d-%d", first, last); } if (nfirst <= lastlast + 1) { if (nlast >= first - 1) { res = set[0..lastidx-1] + lastfirst + "-" + last; if (nextidx) res += set[nextidx-1..]; return res; } return set[0..lastidx-1] + lastfirst + "-" + nlast + set[idx-1..]; } if (nlast >= first - 1) { res = set[0..sidx-1] + nfirst + "-" + last; if (nextidx) res += set[nextidx-1..]; return res; } return set[0..sidx-1] + nfirst + "-" + nlast + set[idx-1..]; } if (nlast <= last) return set; lastidx = idx; lastfirst = first; lastlast = last; idx = nextidx; } while (idx); if (nfirst <= lastlast + 1) return set[0..lastidx-1] + lastfirst + "-" + nlast; else return set + "," + nfirst + "-" + nlast; } string set_remove(string set, int number) { int idx, nextidx; if(!valid_set(set)) error(sprintf("Invalid set in set_remove: %s\n",set)); if (set == "") return set; idx = 0; do { string part; int first, last; nextidx = member_array(',', set, idx) + 1; if (!nextidx) part = set[idx..]; else part = set[idx..nextidx-2]; sscanf(part, "%d-%d", first, last); if (number <= last) { string res; if (number < first) return set; if (number == last) { if (number == first) { if (idx) { res = set[0..idx-1]; if (nextidx) res += set[nextidx-1..]; } else { res = (nextidx ? set[nextidx..] : ""); } return res; } res = set[0..idx-1] + first + "-" + (last - 1); if (nextidx) res += set[nextidx-1..]; return res; } if (number == first) { res = set[0..idx-1] + (first + 1) + "-" + last; if (nextidx) res += set[nextidx-1..]; return res; } res = set[0..idx-1] + first + "-" + (number - 1) + "," + (number + 1) + "-" + last; if (nextidx) res += set[nextidx-1..]; return res; } idx = nextidx; } while (idx); return set; } int set_member(string set, int number) { string array set_parts; if(!valid_set(set)) error(sprintf("Invalid set in set_member: %s\n",set)); set_parts=explode(set,","); foreach(string element in set_parts) { int first; int last; sscanf(element,"%d-%d",first,last); if(number<first) continue; if(number<=last) return 1; } } /* More filter() friendly interface */ int member_set(int number,string set) { return set_member(set,number); } string set_union(string set1, string set2) { string res = ""; int f1 = -1, f2 = -1, l1, l2, handled; if(!valid_set(set1)) error(sprintf("Invalid first set in set_union: %s\n",set1)); if(!valid_set(set2)) error(sprintf("Invalid second set in set_union: %s\n",set2)); sscanf(set1, "%d-%d%s", f1, l1, set1); if (set1[0] == ',') set1 = set1[1..]; sscanf(set2, "%d-%d%s", f2, l2, set2); if (set2[0] == ',') set2 = set2[1..]; handled = 0; while (f1 != -1 && f2 != -1) { if (l1 < f2) { res += (res == "" ? "" : ",") + f1 + "-" + l1; f1 = -1; sscanf(set1, "%d-%d%s", f1, l1, set1); if (set1[0] == ',') set1 = set1[1..]; } else if (l2 < f1) { res += (res == "" ? "" : ",") + f2 + "-" + l2; f2 = -1; sscanf(set2, "%d-%d%s", f2, l2, set2); if (set2[0] == ',') set2 = set2[1..]; } else { int a = (f1 < f2 ? f1 : f2); int b = (l1 > l2 ? l1 : l2); while (1) { if (f1 != -1 && f1 <= b) { f1 = -1; sscanf(set1, "%d-%d%s", f1, l1, set1); if (set1[0] == ',') set1 = set1[1..]; if (f1 <= b && l1 > b) b = l1; } else if (f2 != -1 && f2 <= b) { f2 = -1; sscanf(set2, "%d-%d%s", f2, l2, set2); if (set2[0] == ',') set2 = set2[1..]; if (f2 <= b && l2 > b) b = l2; } else break; } res += (res == "" ? "" : ",") + a + "-" + b; } } if (f1 != -1) res += (res == "" ? "" : ",") + f1 + "-" + l1; if (f2 != -1) res += (res == "" ? "" : ",") + f2 + "-" + l2; if (set1 != "") res += (res == "" ? "" : ",") + set1; if (set2 != "") res += (res == "" ? "" : ",") + set2; return res; } string set_difference(string set1, string set2) { string res = ""; int f1 = -1, f2 = -1, l1, l2; if(!valid_set(set1)) error(sprintf("Invalid first set in set_difference: %s\n",set1)); if(!valid_set(set2)) error(sprintf("Invalid second set in set_difference: %s\n",set2)); sscanf(set1, "%d-%d%s", f1, l1, set1); sscanf(set2, "%d-%d%s", f2, l2, set2); while (f1 != -1) { if(set1[0]==',') set1=set1[1..]; if(set2[0]==',') set2=set2[1..]; if(f2==-1) { /* This might want to be reconstructed as string addition to * conform with the rest of the function, but right now it * works, and I can deal better w/ sprintf()S -- Tigran */ res+=sprintf("%s%i-%i%s%s", (res==""?"":","), f1, l1, set1==""?"":",", set1); f1=-1; continue; } else if (l1 < f2) { res += (res == "" ? "" : ",") + f1 + "-" + l1; f1 = -1; sscanf(set1, "%d-%d%s", f1, l1, set1); if (set1[0] == ',') set1 = set1[1..]; } else if (l2 < f1) { f2 = -1; sscanf(set2, "%d-%d%s", f2, l2, set2); if (set2[0] == ',') set2 = set2[1..]; } else { if (f1 < f2) { res += (res == "" ? "" : ",") + f1 + "-" + (f2-1); f1=-1; sscanf(set1,"%d-%d%s",f1,l1,set1); } if (l2 < l1) { f1 = l2 + 1; f2=-1; sscanf(set2, "%d-%d%s", f2, l2, set2); } else if (l1 < l2) { f1 = -1; sscanf(set1, "%d-%d%s", f1, l1, set1); if (set1[0] == ',') set1 = set1[1..]; } else if ( f1==f2 ) { if(l1==l2) { f1=-1; sscanf(set1,"%d-%d%s",f1,l1,set1); f2=-1; sscanf(set2,"%d-%d%s",f2,l2,set2); } } else { f2 = -1; sscanf(set2, "%d-%d%s", f2, l2, set2); if (set2[0] == ',') set2 = set2[1..]; } } } return res; } string set_intersection(string set1, string set2) { string res = ""; int f1 = -1, f2 = -1, l1, l2; if(!valid_set(set1)) error(sprintf("Invalid first set in set_intersection: %s\n",set1)); if(!valid_set(set2)) error(sprintf("Invalid second set in set_intersection: %s\n",set2)); sscanf(set1, "%d-%d%s", f1, l1, set1); if (set1[0] == ',') set1 = set1[1..]; sscanf(set2, "%d-%d%s", f2, l2, set2); if (set2[0] == ',') set2 = set2[1..]; while (f1 != -1 && f2 != -1) { if (l1 < f2) { f1 = -1; sscanf(set1, "%d-%d%s", f1, l1, set1); if (set1[0] == ',') set1 = set1[1..]; } else if (l2 < f1) { f2 = -1; sscanf(set2, "%d-%d%s", f2, l2, set2); if (set2[0] == ',') set2 = set2[1..]; } else { res += (res == "" ? "" : ",") + (f1 > f2 ? f1 : f2) + "-" + (l1 < l2 ? l1 : l2); if (l1 < l2) { f1 = -1; sscanf(set1, "%d-%d%s", f1, l1, set1); if (set1[0] == ',') set1 = set1[1..]; } else { f2 = -1; sscanf(set2, "%d-%d%s", f2, l2, set2); if (set2[0] == ',') set2 = set2[1..]; } } } return res; } int set_min(string set) { int ret = 0; if(!valid_set(set)) error(sprintf("Invalid set in set_min: %s\n",set)); sscanf(set, "%d", ret); return ret; } int set_max(string set) { int idx = strsrch(set, ",", -1); int ret; if(!valid_set(set)) error(sprintf("Invalid set in set_max: %s\n",set)); sscanf(set[idx+1..], "%*d-%d", ret); return ret; } int set_count(string set) { int f, l; int ret = 0; if(!valid_set(set)) error(sprintf("Invalid set in set_count: %s\n",set)); while (strlen(set)) { sscanf(set, "%d-%d%s", f, l, set); if (set[0] == ',') set = set[1..]; ret += l - f + 1; } return ret; }