|
|
1.1 ! root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ ! 2: ! 3: /* ! 4: * $Header: b1lta.c,v 1.4 85/08/22 16:49:05 timo Exp $ ! 5: */ ! 6: ! 7: /* Access and update lists and tables */ ! 8: ! 9: #include "b.h" ! 10: #include "b0con.h" ! 11: #include "b1obj.h" ! 12: #ifndef INTEGRATION ! 13: #include "b1btr.h" ! 14: #include "b1val.h" ! 15: #include "b3err.h" ! 16: #include "b3scr.h" /* For at_nwl */ ! 17: #endif ! 18: #include "b1tlt.h" ! 19: ! 20: #ifndef INTEGRATION ! 21: ! 22: #ifndef DEBUG ! 23: #define check(v, where) /*nothing*/ ! 24: #endif DEBUG ! 25: ! 26: #define IsInner(p) (Flag(p) == Inner) ! 27: #define IsBottom(p) (Flag(p) == Bottom) ! 28: ! 29: #define _Pxitm(p, l, iw) (IsInner(p) ? Piitm(p, l, iw) : Pbitm(p, l, iw)) ! 30: ! 31: Hidden itemptr Pxitm(p, l, iw) btreeptr p; intlet l, iw; { ! 32: return _Pxitm(p, l, iw); ! 33: } ! 34: ! 35: #define Inil ((itemptr)0) ! 36: ! 37: #define Incr(p, n) ((p) += (n)) ! 38: ! 39: Visible width itemwidth[4]= {Cw, Lw, Tw, Kw}; ! 40: ! 41: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 42: ! 43: typedef struct { ! 44: btreeptr s_ptr; ! 45: int s_lim; ! 46: } finger[Maxheight], *fingertip; ! 47: ! 48: #define Snil ((fingertip)0) ! 49: ! 50: #define Push(s, p, l) ((s)->s_ptr= (p), ((s)->s_lim= (l)), (s)++) ! 51: #define Top(s, p, l) ((p)= ((s)-1)->s_ptr, (l)= ((s)-1)->s_lim) ! 52: #define Drop(s) (--(s)) ! 53: #define Pop(s, p, l) (--(s), (p)= (s)->s_ptr, (l)= (s)->s_lim) ! 54: /* Pop(s, p, l) is equivalent to Top(s, p, l); Drop(s) */ ! 55: ! 56: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 57: ! 58: Visible fingertip unzip(p, at, s) btreeptr p; int at; fingertip s; { ! 59: int syz; intlet l; ! 60: if (p == Bnil) return s; ! 61: for (;;) { ! 62: if (at <= 0) l= 0; ! 63: else if (at >= Size(p)) l= Lim(p); ! 64: else if (IsInner(p)) { ! 65: l= 0; ! 66: while (at > (syz= Size(Ptr(p, l)))) { ! 67: ++l; ! 68: at -= syz+1; ! 69: } ! 70: } ! 71: else if (at >= Lim(p)) l= Lim(p) - 1; /* for Irange/Crange */ ! 72: else l= at; /* Assume Bottom */ ! 73: Push(s, p, l); ! 74: if (!IsInner(p)) break; ! 75: p= Ptr(p, l); ! 76: } ! 77: return s; ! 78: } ! 79: ! 80: Visible Procedure cpynptrs(to, from, n) btreeptr *to, *from; int n; { ! 81: while (--n >= 0) { ! 82: *to= copybtree(*from); ! 83: Incr(to, 1); ! 84: Incr(from, 1); ! 85: } ! 86: } ! 87: ! 88: Visible int movnptrs(to, from, n) btreeptr *to, *from; int n; { ! 89: int syz= 0; /* Collects sum of sizes */ ! 90: while (--n >= 0) { ! 91: *to= *from; ! 92: syz += Size(*from); ! 93: Incr(to, 1); ! 94: Incr(from, 1); ! 95: } ! 96: return syz; ! 97: } ! 98: ! 99: /* The following two routines may prove machine-dependent when moving ! 100: N pointers is not equivalent to moving N*sizeof(pointer) characters. ! 101: Also, the latter may be slower. */ ! 102: ! 103: Visible Procedure movnitms(to, from, n, iw) itemptr to, from; intlet n, iw; { ! 104: register char *t= (char *)to, *f= (char *)from; ! 105: n *= iw; ! 106: while (--n >= 0) *t++ = *f++; ! 107: } ! 108: ! 109: Hidden Procedure shift(p, l, iw) btreeptr p; intlet l, iw; { ! 110: /* Move items and pointers from l upwards one to the right */ ! 111: btreeptr *to, *from; ! 112: intlet n= (Lim(p)-l) * iw; bool inner= IsInner(p); ! 113: char *f= (char *) Pxitm(p, Lim(p), iw); ! 114: char *t= f+iw; ! 115: while (--n >= 0) *--t = *--f; ! 116: if (inner) { ! 117: from= &Ptr(p, Lim(p)); ! 118: to= from; ! 119: Incr(to, 1); ! 120: n= Lim(p)-l; ! 121: while (--n >= 0) { ! 122: *to= *from; ! 123: Incr(to, -1); ! 124: Incr(from, -1); ! 125: } ! 126: } ! 127: } ! 128: ! 129: Visible Procedure cpynitms(to, from, n, it) itemptr to, from; intlet n, it; { ! 130: intlet i, iw= Itemwidth(it); ! 131: movnitms(to, from, n, iw); ! 132: switch (it) { ! 133: case Lt: ! 134: case Kt: ! 135: case Tt: ! 136: for (i= 0; i < n; ++i) { ! 137: copy(Keyval(to)); ! 138: if (it == Tt) copy(Ascval(to)); ! 139: else if (it == Kt) Ascval(to)= Vnil; ! 140: to= (itemptr) ((char*)to + iw); ! 141: } ! 142: } ! 143: } ! 144: ! 145: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 146: ! 147: /* Uflow uses a character array to hold the items. This may be wrong. */ ! 148: ! 149: Visible Procedure uflow(n, l, cbuf, pbuf, it) ! 150: intlet n, l; char cbuf[]; btreeptr pbuf[]; intlet it; { ! 151: char ncbuf[3*Maxbottom*sizeof(item)], *cp= ncbuf; ! 152: btreeptr npbuf[3*Maxinner], *pp= npbuf, q; ! 153: intlet iw= Itemwidth(it); bool inner= IsInner(pbuf[0]); ! 154: intlet i, j, k, nn, l1= l>0 ? l-1 : l, l2= l<n ? l+1 : l; ! 155: for (i= l1; i <= l2; ++i) { ! 156: q= pbuf[i]; j= Lim(q); ! 157: cpynitms((itemptr)cp, Pxitm(q, 0, iw), j, it); ! 158: cp += j*iw; ! 159: if (inner) { ! 160: cpynptrs(pp, &Ptr(q, 0), j+1); ! 161: Incr(pp, j+1); ! 162: } ! 163: if (i < l2) { ! 164: movnitms((itemptr)cp, (itemptr)(cbuf+i*iw), 1, iw); ! 165: cp += iw; ! 166: } ! 167: relbtree(q, it); ! 168: } ! 169: nn= (cp-ncbuf)/iw; ! 170: k= inner ? Maxinner : Maxbottom; ! 171: if (nn <= k) k= 1; ! 172: else if (nn <= 2*k) k= 2; ! 173: else k= 3; ! 174: /* (k <= l2-l1+1) */ ! 175: cp= ncbuf; pp= npbuf; ! 176: for (i= 0; i < k; ++i) { ! 177: if (i > 0) { ! 178: movnitms((itemptr)(cbuf+(l1+i-1)*iw), (itemptr)cp, 1, iw); ! 179: cp += iw; ! 180: --nn; ! 181: } ! 182: pbuf[l1+i]= q= grabbtreenode(inner ? Inner : Bottom, it); ! 183: Lim(q)= Size(q)= j= nn/(k-i); nn -= j; ! 184: movnitms(Pxitm(q, 0, iw), (itemptr)cp, j, iw); ! 185: cp += j*iw; ! 186: if (inner) { ! 187: Size(q) += movnptrs(&Ptr(q, 0), pp, j+1); ! 188: Incr(pp, j+1); ! 189: } ! 190: } ! 191: if (k < l2-l1+1) { ! 192: movnitms((itemptr)(cbuf+(l1+k-1)*iw), (itemptr)(cbuf+l2*iw), n-l2, iw); ! 193: VOID movnptrs(pbuf+l1+k, pbuf+l2+1, n-l2); ! 194: n -= l2-l1+1 - k; ! 195: } ! 196: return n; ! 197: } ! 198: ! 199: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 200: ! 201: /* Low level access routines */ ! 202: ! 203: /* Meaning of 'flags' parameter to searchkey: */ ! 204: #define NORMAL 0 ! 205: #define UNIQUE 1 /* uniquify visited nodes */ ! 206: #define DYAMAX 2 /* special for dyadic max (= previous element) */ ! 207: #define DYAMIN 4 /* special for dyadic min (= next element) */ ! 208: ! 209: Hidden bool searchkey(v, pw, flags, ft) ! 210: value v, *pw; int flags; fingertip *ft; { ! 211: btreeptr p, *pp; ! 212: intlet l, mid, h, it= Itemtype(*pw), iw= Itemwidth(it); ! 213: bool inner; relation r; ! 214: pp= &Root(*pw); ! 215: if (*pp == Bnil) return No; ! 216: if (flags&UNIQUE) { ! 217: killranges(pw); ! 218: uniql(pw); ! 219: pp= &Root(*pw); ! 220: } ! 221: for (;;) { ! 222: if (flags&UNIQUE) uniqlbtreenode(pp, it); ! 223: p= *pp; ! 224: inner= IsInner(p); ! 225: l= 0; h= Lim(p); ! 226: r= 1; /* For the (illegal?) case that there are no items */ ! 227: while (l < h) { /* Binary search in {l..h-1} */ ! 228: mid= (l+h)/2; ! 229: r= compare(v, Keyval(Pxitm(p, mid, iw))); ! 230: if (!comp_ok) return No; ! 231: if (r == 0) { /* Found it */ ! 232: if (flags&(DYAMIN|DYAMAX)) { ! 233: /* Pretend not found */ ! 234: if (flags&DYAMIN) r= 1; ! 235: else r= -1; ! 236: } ! 237: else { /* Normal case, report success */ ! 238: l= mid; ! 239: break; ! 240: } ! 241: } ! 242: if (r < 0) h= mid; /* Continue in {l..mid-1} */ ! 243: else if (r > 0) l= mid+1; /* Cont. in {mid+1..h-i} */ ! 244: } ! 245: Push(*ft, p, l); ! 246: if (r == 0) return Yes; ! 247: if (!inner) { ! 248: switch (Flag(p)) { ! 249: case Irange: return h > 0 && l < Lim(p) && integral(v); ! 250: case Crange: return h > 0 && l < Lim(p) && character(v); ! 251: default: case Bottom: return No; ! 252: } ! 253: } ! 254: pp= &Ptr(p, l); ! 255: } ! 256: } ! 257: ! 258: Hidden Procedure killranges(pv) value *pv; { ! 259: btreeptr p= Root(*pv); ! 260: if (p == Bnil) return; ! 261: switch (Flag(p)) { ! 262: case Crange: killCrange(p, pv); break; ! 263: case Irange: killIrange(p, pv); break; ! 264: } ! 265: } ! 266: ! 267: Hidden Procedure killCrange(p, pv) btreeptr p; value *pv; { ! 268: value w; intlet lwbchar= Lwbchar(p), upbchar= Upbchar(p); ! 269: release(*pv); ! 270: *pv= mk_elt(); ! 271: do { ! 272: w= mkchar(lwbchar); ! 273: insert(w, pv); ! 274: release(w); ! 275: } while (++lwbchar <= upbchar); ! 276: } ! 277: ! 278: Hidden Procedure killIrange(p, pv) btreeptr p; value *pv; { ! 279: value w, lwb= copy(Lwbval(p)), upb= copy(Upbval(p)); ! 280: release(*pv); ! 281: *pv= mk_elt(); ! 282: do { ! 283: insert(lwb, pv); ! 284: if (compare(lwb, upb) >= 0) break; ! 285: w= lwb; ! 286: lwb= sum(lwb, one); ! 287: release(w); ! 288: } while (still_ok); ! 289: release(lwb); ! 290: release(upb); ! 291: } ! 292: ! 293: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 294: ! 295: Hidden btreeptr rem(f, ft, it) fingertip f, ft; intlet it; { ! 296: btreeptr p, q, *pp; itemptr ip; intlet l, iw= Itemwidth(it); ! 297: bool inner, underflow; ! 298: Pop(ft, p, l); ! 299: inner= IsInner(p); ! 300: if (!inner) ip= Pbitm(p, l, iw); ! 301: else { ! 302: ip= Piitm(p, l, iw); ! 303: do { ! 304: Push(ft, p, l); ! 305: uniqlbtreenode(pp= &Ptr(p, l), it); ! 306: p= *pp; ! 307: l= Lim(p); ! 308: } while (IsInner(p)); ! 309: inner= No; ! 310: l -= 2; /* So the movnitms below works fine */ ! 311: } ! 312: release(Keyval(ip)); ! 313: if (it == Tt || it == Kt) release(Ascval(ip)); ! 314: --Lim(p); ! 315: movnitms(ip, Pbitm(p, l+1, iw), Lim(p)-l, iw); ! 316: for (;;) { ! 317: underflow= Lim(p) < (inner ? Mininner : Minbottom); ! 318: --Size(p); ! 319: if (ft == f) break; ! 320: Pop(ft, p, l); ! 321: if (underflow) ! 322: Lim(p)= uflow(Lim(p), l, (string)Piitm(p, 0, iw), &Ptr(p, 0), it); ! 323: inner= Yes; ! 324: } ! 325: if (Lim(p) == 0) { /* Reduce tree level */ ! 326: q= p; ! 327: p= inner ? copybtree(Ptr(p, 0)) : Bnil; ! 328: relbtree(q, it); ! 329: } ! 330: return p; ! 331: } ! 332: ! 333: Hidden btreeptr ins(ip, f, ft, it) itemptr ip; fingertip f, ft; intlet it; { ! 334: item new, old; btreeptr p, q= Bnil, pq, oldq, *pp; ! 335: intlet l, iw= Itemwidth(it), nn, np, nq; bool inner, overflow; ! 336: if (ft == f) { ! 337: /* unify with rest? */ ! 338: p= grabbtreenode(Bottom, it); ! 339: movnitms(Pbitm(p, 0, iw), ip, 1, iw); ! 340: Lim(p)= Size(p)= 1; ! 341: return p; ! 342: } ! 343: Pop(ft, p, l); ! 344: while (IsInner(p)) { ! 345: Push(ft, p, l); ! 346: uniqlbtreenode(pp= &Ptr(p, l), it); ! 347: p= *pp; ! 348: l= Lim(p); ! 349: } ! 350: overflow= Yes; inner= No; ! 351: for (;;) { ! 352: pq= p; ! 353: if (overflow) { ! 354: oldq= q; ! 355: movnitms(&old, ip, 1, iw); ! 356: ip= &new; ! 357: overflow= Lim(p) == (inner ? Maxinner : Maxbottom); ! 358: if (overflow) { ! 359: nn= Lim(p); np= nn/2; nq= nn-np-1; ! 360: q= grabbtreenode(inner ? Inner : Bottom, it); ! 361: Size(q)= Lim(q)= nq; ! 362: movnitms(&new, Pxitm(p, np, iw), 1, iw); ! 363: movnitms(Pxitm(q, 0, iw), Pxitm(p, np+1, iw), nq, iw); ! 364: if (inner) ! 365: Size(q) += movnptrs(&Ptr(q, 0), &Ptr(p, np+1), nq+1); ! 366: Lim(p)= np; ! 367: Size(p) -= Size(q)+1; ! 368: if (l > np) { ! 369: l -= np+1; ! 370: pq= q; ! 371: } ! 372: } ! 373: shift(pq, l, iw); ! 374: movnitms(Pxitm(pq, l, iw), &old, 1, iw); ! 375: ++Lim(pq); ! 376: if (inner) { ! 377: Size(p) -= Size(oldq); ! 378: Size(pq) += movnptrs(&Ptr(pq, l+1), &oldq, 1); ! 379: } ! 380: } ! 381: ++Size(pq); ! 382: if (ft == f) break; ! 383: Pop(ft, p, l); ! 384: inner= Yes; ! 385: } ! 386: if (overflow) ! 387: p= mknewroot(p, ip, q, it); ! 388: return p; ! 389: } ! 390: ! 391: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 392: ! 393: /* Tables */ ! 394: ! 395: Visible Procedure replace(a, pt, k) value a, *pt, k; { ! 396: item new; finger f; fingertip ft= f; btreeptr p; value *pp; ! 397: intlet it, iw, l; ! 398: check(*pt, " (replace in)"); ! 399: if (Is_ELT(*pt)) { (*pt)->type= Tab; Itemtype(*pt)= Tt; } ! 400: it= Itemtype(*pt); ! 401: if (searchkey(k, pt, UNIQUE, &ft)) { ! 402: iw= Itemwidth(it); ! 403: Pop(ft, p, l); ! 404: pp= &Ascval(Pxitm(p, l, iw)); ! 405: release(*pp); ! 406: *pp= copy(a); ! 407: } ! 408: else { ! 409: if (!comp_ok) return; ! 410: Keyval(&new)= copy(k); Ascval(&new)= copy(a); ! 411: Root(*pt)= ins(&new, f, ft, it); ! 412: } ! 413: check(*pt, " (replace out)"); ! 414: } ! 415: ! 416: Visible /*bool*/ delete(pt, k) value *pt, k; { ! 417: finger f; fingertip ft= f; intlet it= Itemtype(*pt); ! 418: check(*pt, " (delete in)"); ! 419: if (!searchkey(k, pt, UNIQUE, &ft)) return No; ! 420: Root(*pt)= rem(f, ft, it); ! 421: check(*pt, " (delete out)"); ! 422: return Yes; ! 423: } ! 424: ! 425: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 426: ! 427: /* Lists */ ! 428: ! 429: Visible Procedure insert(v, pl) value v, *pl; { ! 430: item new; finger f; fingertip ft= f; intlet it= Itemtype(*pl); ! 431: check(*pl, " (insert in)"); ! 432: if (Is_ELT(*pl)) (*pl)->type= Lis; ! 433: VOID searchkey(v, pl, UNIQUE, &ft); ! 434: if (!comp_ok) return; ! 435: Keyval(&new)= copy(v); Ascval(&new)= Vnil; ! 436: Root(*pl)= ins(&new, f, ft, it); ! 437: check(*pl, " (insert out)"); ! 438: } ! 439: ! 440: Visible Procedure remove(v, pl) value v, *pl; { ! 441: if (!delete(pl, v) && still_ok) ! 442: error(MESS(100, "removing non-existent list entry")); ! 443: } ! 444: ! 445: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 446: ! 447: /* Miscellaneous accesses */ ! 448: ! 449: Hidden itemptr findkey(key, pv, flags) value key, *pv; int flags; { ! 450: finger f; fingertip ft= f; btreeptr p; ! 451: intlet it= Itemtype(*pv), iw= Itemwidth(it), l; ! 452: if (!searchkey(key, pv, flags, &ft)) return Inil; ! 453: Pop(ft, p, l); ! 454: return Pxitm(p, l, iw); ! 455: } ! 456: ! 457: Visible value associate(t, k) value t, k; { /* t[k] */ ! 458: itemptr ip; ! 459: if (!Is_table(t)) { ! 460: error(MESS(101, "in t[k], t is not a table")); ! 461: return Vnil; ! 462: } ! 463: ip= findkey(k, &t, NORMAL); ! 464: if (!ip) { ! 465: if (still_ok) /* Could be type error; then shut up! */ ! 466: error(MESS(102, "key not in table")); ! 467: return Vnil; ! 468: } ! 469: return copy(Ascval(ip)); ! 470: } ! 471: ! 472: Visible value* adrassoc(t, k) value t, k; { /* &t[k] */ ! 473: itemptr ip= findkey(k, &t, NORMAL); ! 474: if (!ip) return Pnil; ! 475: return &Ascval(ip); ! 476: } ! 477: ! 478: Visible bool uniq_assoc(t, k) value t, k; { /* uniql(&t[k]) */ ! 479: itemptr ip= findkey(k, &t, UNIQUE); ! 480: if (ip == Inil) return No; ! 481: uniql(&Ascval(ip)); ! 482: return Yes; ! 483: } ! 484: ! 485: Visible bool in_keys(k, t) value k, t; { /* k in keys t */ ! 486: return findkey(k, &t, NORMAL) != Inil; ! 487: } ! 488: ! 489: Visible value keys(t) value t; { /* keys t */ ! 490: value v; ! 491: if (!Is_table(t)) { ! 492: error(MESS(103, "in keys t, t is not a table")); ! 493: return Vnil; ! 494: } ! 495: v= grab_tlt(Lis, Kt); ! 496: Root(v)= copybtree(Root(t)); ! 497: return v; ! 498: } ! 499: ! 500: /* WARNING! The following routine is not reentrant, since (for range lists) ! 501: it may return a pointer to static storage. */ ! 502: ! 503: Hidden itemptr getkth(k, v) int k; value v; { ! 504: finger f; fingertip ft; btreeptr p; ! 505: intlet it= Itemtype(v), iw= Itemwidth(it), l; ! 506: static item baked; value vk; ! 507: if (Root(v) == Bnil) return Inil; ! 508: ft= unzip(Root(v), k, f); ! 509: do { ! 510: if (ft == f) return Inil; ! 511: Pop(ft, p, l); ! 512: } while (l >= Lim(p)); ! 513: switch (Flag(p)) { ! 514: default: ! 515: case Inner: ! 516: case Bottom: ! 517: return Pxitm(p, l, iw); ! 518: case Irange: ! 519: release(Keyval(&baked)); ! 520: Keyval(&baked)= sum(Lwbval(p), vk= mk_integer(k)); ! 521: release(vk); ! 522: return &baked; ! 523: case Crange: ! 524: release(Keyval(&baked)); ! 525: Keyval(&baked)= mkchar(Lwbchar(p) + k); ! 526: return &baked; ! 527: } ! 528: } ! 529: ! 530: Visible value* key(v, k) value v; intlet k; { /* &(++k th'of keys v) */ ! 531: itemptr ip= getkth(k, v); ! 532: return ip ? &Keyval(ip) : Pnil; ! 533: } ! 534: ! 535: Visible value* assoc(v, k) value v; intlet k; { /* &v[++k th'of keys v] */ ! 536: itemptr ip= getkth(k, v); ! 537: return ip ? &Ascval(ip) : Pnil; ! 538: } ! 539: ! 540: Visible value thof(k, v) int k; value v; { /* k th'of v */ ! 541: itemptr ip= getkth(k-1, v); ! 542: if (!ip) return Vnil; ! 543: switch (Type(v)) { ! 544: case Tex: return mkchar(Charval(ip)); ! 545: case Lis: return copy(Keyval(ip)); ! 546: case Tab: return copy(Ascval(ip)); ! 547: default: return Vnil; ! 548: } ! 549: } ! 550: ! 551: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 552: ! 553: /* Compare B-trees. Should use fingers, but to keep things simple ! 554: (especially in the presence of range type nodes), doesn't. This ! 555: makes its behaviour O(N log N), where it could be O(N), alas. */ ! 556: ! 557: /* WARNING! getkth may return a pointer to static storage (when retrieving ! 558: elements from a range list). Therefore after the second call to getkth, ! 559: the return value of the first may be invalid, but only for lists. ! 560: So we extract the 'Key' values immediately after the call to getkth. */ ! 561: ! 562: Visible relation comp_tlt(u, v) value u, v; { ! 563: itemptr up, vp; int k, ulen, vlen, len; relation r= 0; ! 564: bool tex= Is_text(u), tab= Is_table(u); ! 565: value key_u; ! 566: len= ulen= Tltsize(u); vlen= Tltsize(v); ! 567: if (vlen < len) len= vlen; ! 568: for (k= 0; k < len; ++k) { ! 569: up= getkth(k, u); ! 570: if (!tex) key_u= copy(Keyval(up)); ! 571: vp= getkth(k, v); ! 572: if (tex) r= Charval(up) - Charval(vp); ! 573: else { ! 574: r= compare(key_u, Keyval(vp)); ! 575: release(key_u); ! 576: if (tab && r == 0) ! 577: r= compare(Ascval(up), Ascval(vp)); ! 578: } ! 579: if (r != 0) break; ! 580: } ! 581: if (r == 0) r= ulen - vlen; ! 582: return r; ! 583: } ! 584: ! 585: /* Compare texts. When both texts are bottom nodes, compare with ! 586: strncmp(), to speed up the most common use (look-up by the ! 587: system of tags in a symbol table). Otherwise, call comp_tlt(). */ ! 588: ! 589: Visible relation comp_text(u, v) value u, v; { ! 590: btreeptr p, q; int len; relation r; ! 591: if (!Is_text(u) || !Is_text(v)) syserr(MESS(104, "comp_text")); ! 592: p= Root(u), q= Root(v); ! 593: if (p EQ Bnil) return (q EQ Bnil) ? 0 : -1; ! 594: if (q EQ Bnil) return 1; ! 595: if (Flag(p) EQ Bottom && Flag(q) EQ Bottom) { ! 596: len= Lim(p); ! 597: if (Lim(q) < len) len= Lim(q); ! 598: r= strncmp(&Bchar(p, 0), &Bchar(q, 0), len); ! 599: if (r NE 0) return r; ! 600: return Lim(p) - Lim(q); ! 601: } ! 602: return comp_tlt(u, v); ! 603: } ! 604: ! 605: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 606: ! 607: /* Range type nodes */ ! 608: ! 609: Visible value mk_numrange(lwb, upb) value lwb, upb; { ! 610: value lis; ! 611: btreeptr proot; ! 612: ! 613: lis= grab_tlt(Lis, Lt); ! 614: if (numcomp(lwb, upb) > 0) ! 615: Root(lis)= Bnil; ! 616: else { ! 617: Root(lis)= proot= grabbtreenode(Irange, Lt); ! 618: Lwbval(proot)= copy(lwb); ! 619: Upbval(proot)= copy(upb); ! 620: set_size_and_lim(proot); ! 621: } ! 622: return(lis); ! 623: } ! 624: ! 625: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 626: ! 627: Visible value mk_charrange(lwb, upb) value lwb, upb; { ! 628: value lis; ! 629: btreeptr proot; ! 630: intlet rsyz; ! 631: ! 632: lis= grab_tlt(Lis, Lt); ! 633: rsyz= Bchar(Root(upb), 0) - Bchar(Root(lwb), 0) + 1; ! 634: if (rsyz <= 0) ! 635: Root(lis)= Bnil; ! 636: else { ! 637: Root(lis)= proot= grabbtreenode(Crange, Lt); ! 638: Size(proot)= rsyz; ! 639: Lim(proot)= rsyz > 1 ? 2 : 1; ! 640: Lwbval(proot)= copy(lwb); ! 641: Upbval(proot)= copy(upb); ! 642: } ! 643: return lis; ! 644: } ! 645: ! 646: ! 647: /* set size and lim for integer range node */ ! 648: ! 649: Hidden Procedure set_size_and_lim(pnode) btreeptr pnode; { ! 650: value uml, uml1; ! 651: ! 652: uml= diff(Upbval(pnode), Lwbval(pnode)); ! 653: uml1= sum(uml, one); ! 654: if (large(uml1)) { ! 655: Size(pnode)= Bigsize; ! 656: Lim(pnode)= 2; ! 657: error(MESS(105, "creating list of too many entries")); ! 658: } ! 659: else { ! 660: Size(pnode)= intval(uml1); ! 661: Lim(pnode)= Size(pnode) > 1 ? 2 : 1; ! 662: } ! 663: release(uml); ! 664: release(uml1); ! 665: } ! 666: ! 667: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 668: ! 669: /* Dyadic min, max, size of lists */ ! 670: ! 671: Visible value l2min(e, v) value e, v; { /* e min v */ ! 672: finger f; fingertip ft= f; btreeptr p; ! 673: intlet it= Itemtype(v), iw= Itemwidth(it), l; ! 674: VOID searchkey(e, &v, DYAMIN, &ft); ! 675: for (;;) { ! 676: if (ft == f) return Vnil; ! 677: Top(ft, p, l); ! 678: if (l < Lim(p)) { ! 679: switch (Flag(p)) { ! 680: case Inner: ! 681: return copy(Keyval(Piitm(p, l, iw))); ! 682: case Bottom: ! 683: return copy(Keyval(Pbitm(p, l, iw))); ! 684: case Irange: ! 685: if (l == 0) return copy(Lwbval(p)); ! 686: if (integral(e)) return sum(e, one); ! 687: return ceilf(e); ! 688: case Crange: ! 689: if (l == 0) return copy(Lwbval(p)); ! 690: return mkchar(Bchar(Root(e), 0) + 1); ! 691: } ! 692: } ! 693: Drop(ft); ! 694: } ! 695: } ! 696: ! 697: Visible value l2max(e, v) value e, v; { /* e max v */ ! 698: finger f; fingertip ft= f; btreeptr p; ! 699: intlet it= Itemtype(v), iw= Itemwidth(it), l; ! 700: VOID searchkey(e, &v, DYAMAX, &ft); ! 701: for (;;) { ! 702: if (ft == f) return Vnil; ! 703: Top(ft, p, l); ! 704: --l; ! 705: if (l >= 0) { ! 706: switch (Flag(p)) { ! 707: case Inner: ! 708: return copy(Keyval(Piitm(p, l, iw))); ! 709: case Bottom: ! 710: return copy(Keyval(Pbitm(p, l, iw))); ! 711: case Irange: ! 712: if (l == 1) return copy(Upbval(p)); ! 713: if (integral(e)) return diff(e, one); ! 714: return floorf(e); ! 715: case Crange: ! 716: if (l == 1) return copy(Upbval(p)); ! 717: return mkchar(Bchar(Root(e), 0) - 1); ! 718: } ! 719: } ! 720: Drop(ft); ! 721: } ! 722: } ! 723: ! 724: Visible int l2size(e, v) value e, v; { /* e#v */ ! 725: finger f; fingertip ft= f; btreeptr p; ! 726: int count= 0; intlet it= Itemtype(v), iw= Itemwidth(it), l, r; ! 727: VOID searchkey(e, &v, DYAMIN, &ft); ! 728: for (;;) { ! 729: if (ft == f) return count; ! 730: Pop(ft, p, l); ! 731: while (--l >= 0) { ! 732: r= compare(Keyval(Pxitm(p, l, iw)), e); ! 733: if (r != 0) { ! 734: switch (Flag(p)) { ! 735: case Irange: /* See footnote */ ! 736: if (l==0 && count==0 && integral(e)) ! 737: ++count; ! 738: break; ! 739: case Crange: /* See footnote */ ! 740: if (l==0 && count==0 && !character(e)) ! 741: ++count; ! 742: break; ! 743: } ! 744: return count; ! 745: } ! 746: ++count; ! 747: while (IsInner(p)) { ! 748: Push(ft, p, l); ! 749: p= Ptr(p, l); ! 750: l= Lim(p); ! 751: } ! 752: } ! 753: } ! 754: } ! 755: ! 756: /* Clarification of what happens for x#{a..b}: ! 757: * Consider these five cases: x<a; x=a; a<x<b; x=b; b<x. ! 758: * Only the case a<x<b need be treated specially. How do we find which ! 759: * case we're in? ! 760: * Searchkey gives us the following values for l on the stack, respectively: ! 761: * 0; 1; 1; 2; 2. After --l, this becomes -1; 0; 0; 1; 1. ! 762: * In cases x=a or x=b, the compare returns 0, and we go another time ! 763: * through the loop. So when the compare returns r!=0, the value of l ! 764: * is, respectively: -1; -1; 0; 0; 1. The -1 cases in fact don't even ! 765: * get at the compare, and the correct count is returned automatically. ! 766: * So we need to do extra work only if l==0, except if x==b. ! 767: * The latter condition is cared for by count==0 (if x==b, count is ! 768: * surely >= 1; if a<x<b, count is surely 0). This works even when ! 769: * range nodes may be mixed with other node types in one tree. ! 770: */ ! 771: ! 772: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ! 773: ! 774: #ifdef DEBUG ! 775: /* Debug code */ ! 776: ! 777: Hidden Procedure check(v, whence) value v; string whence; { ! 778: if (!still_ok) return; ! 779: switch (Type(v)) { ! 780: case ELT: ! 781: return; ! 782: case Lis: ! 783: case Tab: ! 784: break; ! 785: default: ! 786: error3(MESS(106, "value not a list or table"), Vnil, ! 787: MESSMAKE(whence)); ! 788: return; ! 789: } ! 790: if (Root(v) != Bnil) ! 791: VOID cktree(Inil, Root(v), Inil, Itemtype(v), whence); ! 792: if (!still_ok && !interrupted) { ! 793: dumptree(Root(v), 0, Itemtype(v)); ! 794: printf("\n"); ! 795: fflush(stdout); ! 796: } ! 797: } ! 798: ! 799: Hidden int cktree(left, p, right, it, whence) ! 800: itemptr left; btreeptr p; itemptr right; intlet it; string whence; { ! 801: /* returns size of checked subtree */ ! 802: intlet i, iw= Itemwidth(it); int sz= 0; ! 803: if (!still_ok) return 0; ! 804: if (p == Bnil) { ! 805: error3(MESS(107, "unexpected nil subtree"), Vnil, ! 806: MESSMAKE(whence)); ! 807: return 0; ! 808: } ! 809: switch (Flag(p)) { ! 810: case Inner: ! 811: for (i= 0; i < Lim(p); ++i) { ! 812: sz += 1 + ! 813: cktree(left, Ptr(p, i), Piitm(p, i, iw), it, whence); ! 814: if (!still_ok) return; ! 815: left= Piitm(p, i, iw); ! 816: } ! 817: sz += cktree(left, Ptr(p, i), right, it, whence); ! 818: if (still_ok && sz != Size(p)) ! 819: error3(MESS(108, "size mismatch"), Vnil, ! 820: MESSMAKE(whence)); ! 821: break; ! 822: case Bottom: ! 823: for (i= 0; i < Lim(p); ++i) { ! 824: if (left != Inil && compare(Keyval(left), ! 825: Keyval(Pbitm(p, i, iw))) > 0) { ! 826: error3(MESS(109, "bottom items out of order"), ! 827: Vnil, MESSMAKE(whence)); ! 828: break; ! 829: } ! 830: left= Pbitm(p, i, iw); ! 831: sz++; ! 832: } ! 833: if (still_ok && right != Inil ! 834: && compare(Keyval(left), Keyval(right)) > 0) ! 835: error3(MESS(110, "bottom items out of order"), ! 836: Vnil, MESSMAKE(whence)); ! 837: return sz; ! 838: case Irange: ! 839: if (left != Inil && compare(Keyval(left), Lwbval(p)) > 0 ! 840: || right != Inil ! 841: && compare(Upbval(p), Keyval(right)) > 0) ! 842: error3(MESS(111, "irange items out of order"), Vnil, ! 843: MESSMAKE(whence)); ! 844: sz= Size(p); ! 845: default: ! 846: error3(MESS(112, "bad node type"), Vnil, MESSMAKE(whence)); ! 847: } ! 848: return sz; ! 849: } ! 850: #endif DEBUG ! 851: ! 852: #ifdef NOT_USED ! 853: Visible Procedure e_dumptree(v) value v; { ! 854: check(v, ""); ! 855: if (still_ok) { ! 856: if (!at_nwl) printf("\n"); ! 857: dumptree(Root(v), 0, Itemtype(v)); ! 858: printf("\n"); ! 859: fflush(stdout); ! 860: at_nwl= Yes; ! 861: } ! 862: } ! 863: #endif ! 864: ! 865: Hidden Procedure dumptree(p, indent, it) btreeptr p; intlet indent, it; { ! 866: intlet i, iw= Itemwidth(it); ! 867: if (interrupted) return; ! 868: printf("%*s", 3*indent, ""); ! 869: if (p == Bnil) { printf("<nil>"); return; } ! 870: switch (Flag(p)) { ! 871: case Inner: ! 872: printf("(\n"); ! 873: for (i= 0; !interrupted && i <= Lim(p); ++i) { ! 874: if (i > 0) { ! 875: printf("%*s", 3*indent, ""); ! 876: dumpval(Keyval(Piitm(p, i-1, iw))); ! 877: printf("\n"); ! 878: } ! 879: dumptree(Ptr(p, i), indent+1, it); ! 880: printf("\n"); ! 881: } ! 882: printf("%*s", 3*indent, ""); ! 883: printf(")"); ! 884: break; ! 885: case Bottom: ! 886: printf("["); ! 887: for (i= 0; i < Lim(p); ++i) { ! 888: if (i > 0) printf(" "); ! 889: dumpval(Keyval(Pbitm(p, i, iw))); ! 890: } ! 891: printf("]"); ! 892: break; ! 893: case Irange: ! 894: printf("{"); ! 895: dumpval(Lwbval(p)); ! 896: printf(" .. "); ! 897: dumpval(Upbval(p)); ! 898: printf("}"); ! 899: break; ! 900: default: ! 901: printf("?type='%c'?", Flag(p)); ! 902: break; ! 903: } ! 904: } ! 905: ! 906: Hidden Procedure dumpval(v) value v; { ! 907: if (interrupted) return; ! 908: if (v == Vnil) printf("(nil)"); ! 909: else switch(Type(v)) { ! 910: case Num: case Tex: case Lis: case Tab: case ELT: case Com: ! 911: wri(v, No, No, No); ! 912: break; ! 913: default: ! 914: printf("0x%lx", (long)v); ! 915: } ! 916: } ! 917: ! 918: #else INTEGRATION ! 919: ! 920: /* B lists */ ! 921: ! 922: Visible value list_elem(l, i) value l; intlet i; { ! 923: return List_elem(l, i); ! 924: } ! 925: ! 926: Visible insert(v, ll) value v, *ll; { ! 927: intlet len= Length(*ll); register value *lp, *lq; ! 928: intlet k; register intlet kk; ! 929: if (!Is_list(*ll)) { ! 930: error(MESS(113, "inserting in non-list")); ! 931: return; ! 932: } ! 933: VOID found(list_elem, *ll, v, &k); ! 934: if (Unique(*ll) && !Is_ELT(*ll)) { ! 935: xtndlt(ll, 1); ! 936: lq= Ats(*ll)+len; lp= lq-1; ! 937: for (kk= len; kk > k; kk--) *lq--= *lp--; ! 938: *lq= copy(v); ! 939: } else { ! 940: lp= Ats(*ll); ! 941: release(*ll); ! 942: *ll= grab_lis(++len); ! 943: lq= Ats(*ll); ! 944: for (kk= 0; kk < len; kk++) *lq++= copy (kk == k ? v : *lp++); ! 945: } ! 946: } ! 947: ! 948: Visible remove(v, ll) value v; value *ll; { ! 949: register value *lp, *lq; ! 950: intlet k, len= Length(*ll); ! 951: if (!Is_list(*ll)) ! 952: error(MESS(114, "removing from non-list")); ! 953: else if (len == 0) ! 954: error(MESS(115, "removing from empty list")); ! 955: else if (!found(list_elem, *ll, v, &k)) ! 956: error(MESS(116, "removing non-existing list entry")); ! 957: else { ! 958: lp= Ats(*ll); /* lp[k] = v */ ! 959: if (Unique(*ll)) { ! 960: release(*(lp+=k)); ! 961: for (k= k; k < len; k++) {*lp= *(lp+1); lp++;} ! 962: xtndlt(ll, -1); ! 963: } else { ! 964: intlet kk= k; ! 965: lq= Ats(*ll); ! 966: release(*ll); ! 967: *ll= grab_lis(--len); ! 968: lp= Ats(*ll); ! 969: Overall { ! 970: *lp++= copy (*lq++); ! 971: if (k == kk) lq++; ! 972: } ! 973: } ! 974: } ! 975: } ! 976: ! 977: Visible value mk_numrange(a, z) value a, z; { ! 978: value l= mk_elt(), m= copy(a), n; ! 979: ! 980: while (compare(m, z)<=0) { ! 981: insert(m, &l); ! 982: m= sum(n=m, one); ! 983: release(n); ! 984: } ! 985: release(m); ! 986: return l; ! 987: } ! 988: ! 989: Visible value mk_charrange(av, zv) value av, zv; { ! 990: char a= charval(av), z= charval(zv); ! 991: value l= grab_lis((intlet) (z-a+1)); register value *ep= Ats(l); ! 992: char m[2]; ! 993: m[1]= '\0'; ! 994: for (m[0]= a; m[0] <= z; m[0]++) { ! 995: *ep++= mk_text(m); ! 996: } ! 997: return l; ! 998: } ! 999: ! 1000: /**********************************************************************/ ! 1001: ! 1002: /* B tables */ ! 1003: ! 1004: Visible value* key(v, k) value v; intlet k; { /* k in {0..size-1}; no copy */ ! 1005: return Key(v, k); ! 1006: } ! 1007: ! 1008: Visible value* assoc(v, k) value v; intlet k; { /* k in {0..size-1}; no copy */ ! 1009: return Assoc(v, k); ! 1010: } ! 1011: ! 1012: Visible value associate(v, k) value v; value k; { ! 1013: value *p= adrassoc(v, k); ! 1014: if (p) return copy(*p); ! 1015: error(MESS(117, "key not in table")); ! 1016: return Vnil; ! 1017: } ! 1018: ! 1019: Visible value keys(ta) value ta; { ! 1020: ! 1021: if(!Is_table(ta)) { ! 1022: error(MESS(118, "in keys t, t is not a table")); ! 1023: return grab_lis(0); ! 1024: } else { ! 1025: value li= grab_lis(Length(ta)), *le, *te= (value *)Ats(ta); ! 1026: int k, len= Length(ta); ! 1027: le= (value *)Ats(li); ! 1028: Overall { *le++= copy(Cts(*te++)); } ! 1029: return li; ! 1030: } ! 1031: } ! 1032: ! 1033: Visible value key_elem(t, i) value t; intlet i; { /*The key of the i-th entry*/ ! 1034: return *Key(t, i); ! 1035: } ! 1036: ! 1037: /* adrassoc returns a pointer to the associate, rather than ! 1038: the associate itself, so that the caller can decide if a copy ! 1039: should be taken or not. If the key is not found, Pnil is returned. */ ! 1040: Visible value* adrassoc(t, ke) value t, ke; { ! 1041: intlet where; ! 1042: if (Type(t) != Tab && Type(t) != ELT) { ! 1043: error(MESS(119, "selection on non-table")); ! 1044: return Pnil; ! 1045: } ! 1046: return found(key_elem, t, ke, &where) ? Assoc(t, where) : Pnil; ! 1047: } ! 1048: ! 1049: Visible Procedure uniq_assoc(ta, ke) value ta, ke; { ! 1050: intlet k; ! 1051: if (found(key_elem, ta, ke, &k)) { ! 1052: uniql(Ats(ta)+k); ! 1053: uniql(Assoc(ta,k)); ! 1054: } else syserr(MESS(120, "uniq_assoc called for non-existent table entry")); ! 1055: } ! 1056: ! 1057: Visible Procedure replace(v, ta, ke) value *ta, ke, v; { ! 1058: intlet len= Length(*ta); value *tp, *tq; ! 1059: intlet k, kk; ! 1060: uniql(ta); ! 1061: if (Type(*ta) == ELT) (*ta)->type = Tab; ! 1062: else if (Type(*ta) != Tab) { ! 1063: error(MESS(121, "replacing in non-table")); ! 1064: return; ! 1065: } ! 1066: if (found(key_elem, *ta, ke, &k)) { ! 1067: value *a; ! 1068: uniql(Ats(*ta)+k); ! 1069: a= Assoc(*ta, k); ! 1070: uniql(a); ! 1071: release(*a); ! 1072: *a= copy(v); ! 1073: return; ! 1074: } else { ! 1075: xtndlt(ta, 1); ! 1076: tq= Ats(*ta)+len; tp= tq-1; ! 1077: for (kk= len; kk > k; kk--) *tq--= *tp--; ! 1078: *tq= grab_com(2); ! 1079: Cts(*tq)= copy(ke); ! 1080: Dts(*tq)= copy(v); ! 1081: } ! 1082: } ! 1083: ! 1084: Visible bool in_keys(ke, tl) value ke, tl; { ! 1085: intlet dummy; ! 1086: if (Type(tl) == ELT) return No; ! 1087: if (Type(tl) != Tab) syserr(MESS(122, "in_keys applied to non-table")); ! 1088: return found(key_elem, tl, ke, &dummy); ! 1089: } ! 1090: ! 1091: Visible Procedure delete(tl, ke) value *tl, ke; { ! 1092: intlet len, k; value *tp; ! 1093: if (Type(*tl) == ELT) syserr(MESS(123, "deleting table entry from empty table")); ! 1094: if (Type(*tl) != Tab) syserr(MESS(124, "deleting table entry from non-table")); ! 1095: tp= Ats(*tl); len= Length(*tl); ! 1096: if (!found(key_elem, *tl, ke, &k)) ! 1097: syserr(MESS(125, "deleting non-existent table entry")); ! 1098: if (Unique(*tl)) { ! 1099: release(*(tp+=k)); ! 1100: for (k= k; k < len; k++) {*tp= *(tp+1); tp++;} ! 1101: xtndlt(tl, -1); ! 1102: } else { ! 1103: intlet kk; value *tq= Ats(*tl); ! 1104: release(*tl); ! 1105: *tl= grab_tab(--len); ! 1106: tp= Ats(*tl); ! 1107: for (kk= 0; kk < len; kk++) { ! 1108: *tp++= copy (*tq++); ! 1109: if (kk == k) tq++; ! 1110: } ! 1111: } ! 1112: } ! 1113: ! 1114: #endif INTEGRATION
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.