Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

rq.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) Intel Corporation 2001. All rights reserved.
00003  *
00004  * License is granted to copy, to use, and to make and to use derivative
00005  * works for research and evaluation purposes, provided that Intel is
00006  * acknowledged in all documentation pertaining to any such copy or
00007  * derivative work. Intel grants no other licenses expressed or
00008  * implied. The Intel trade name should not be used in any advertising
00009  * without its written permission. 
00010  *
00011  * INTEL CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
00012  * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
00013  * FOR ANY PARTICULAR PURPOSE.  The software is provided "as is" without
00014  * express or implied warranty of any kind.
00015  *
00016  * These notices must be retained in any copies of any part of this
00017  * software. 
00018  */
00019 
00020 /*
00021  * Copyright (c) 1991-1997 Regents of the University of California.
00022  * All rights reserved.
00023  *
00024  * Redistribution and use in source and binary forms, with or without
00025  * modification, are permitted provided that the following conditions
00026  * are met:
00027  * 1. Redistributions of source code must retain the above copyright
00028  *    notice, this list of conditions and the following disclaimer.
00029  * 2. Redistributions in binary form must reproduce the above copyright
00030  *    notice, this list of conditions and the following disclaimer in the
00031  *    documentation and/or other materials provided with the distribution.
00032  * 3. All advertising materials mentioning features or use of this software
00033  *    must display the following acknowledgement:
00034  *      This product includes software developed by the Computer Systems
00035  *      Engineering Group at Lawrence Berkeley Laboratory.
00036  * 4. Neither the name of the University nor of the Laboratory may be used
00037  *    to endorse or promote products derived from this software without
00038  *    specific prior written permission.
00039  *
00040  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00041  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00042  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00043  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00044  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00045  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00046  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00047  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00048  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00049  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00050  * SUCH DAMAGE.
00051  *
00052  */
00053 
00054 #include "rq.h"
00055 
00056 ReassemblyQueue::seginfo* ReassemblyQueue::freelist_ = NULL;
00057 
00058 ReassemblyQueue::seginfo* ReassemblyQueue::newseginfo()
00059 {
00060         seginfo *s;
00061         
00062         if( (s = freelist_) ){
00063                 freelist_ = s->next_;
00064                 return s;
00065         }else{
00066                 return new seginfo;
00067         }
00068 }
00069 
00070 void ReassemblyQueue::deleteseginfo(ReassemblyQueue::seginfo* s)
00071 {
00072         s->next_ = freelist_;
00073         freelist_ = s;
00074 }
00075 
00076 /*
00077  * unlink a seginfo from its FIFO
00078  */
00079 void
00080 ReassemblyQueue::fremove(seginfo* p)
00081 {
00082         if (hint_ == p)
00083                 hint_ = NULL;
00084 
00085         if (p->prev_)
00086                 p->prev_->next_ = p->next_;
00087         else
00088                 head_ = p->next_;
00089         if (p->next_)
00090                 p->next_->prev_ = p->prev_;
00091         else
00092                 tail_ = p->prev_;
00093 }
00094 
00095 /*
00096  * unlink a seginfo from its LIFO
00097  */
00098 void
00099 ReassemblyQueue::sremove(seginfo* p)
00100 {
00101         if (hint_ == p)
00102                 hint_ = NULL;
00103 
00104         if (p->sprev_)
00105                 p->sprev_->snext_ = p->snext_;
00106         else
00107                 top_ = p->snext_;
00108         if (p->snext_)
00109                 p->snext_->sprev_ = p->sprev_;
00110         else
00111                 bottom_ = p->sprev_;
00112 
00113 }
00114 
00115 /*
00116  * push a seginfo on the LIFO
00117  */
00118 void
00119 ReassemblyQueue::push(seginfo *p)
00120 {
00121         p->snext_ = top_;
00122         p->sprev_ = NULL;
00123         top_ = p;
00124         if (p->snext_)
00125                 p->snext_->sprev_ = p;
00126         else
00127                 bottom_ = p;
00128 }
00129 
00130 /*
00131  * counts: return the # of blks and byte counts in
00132  * them starting at the given node
00133  */
00134 void
00135 ReassemblyQueue::cnts(seginfo *p, int& blkcnt, int& bytecnt)
00136 {
00137         int blks = 0;
00138         int bytes = 0;
00139 
00140         while (p != NULL) {
00141                 ++blks;
00142                 bytes += (p->endseq_ - p->startseq_);
00143                 p = p->next_;
00144         }
00145         blkcnt = blks;
00146         bytecnt = bytes;
00147         return;
00148 }
00149 
00150 
00151 /*
00152  * clear out reassembly queue and stack
00153  */
00154 
00155 void
00156 ReassemblyQueue::clear()
00157 {
00158         // clear stack and end of queue
00159         tail_ = top_ = bottom_ = hint_ = NULL;
00160 
00161         seginfo *p = head_;
00162         while (head_) {
00163                 p = head_;
00164                 head_= head_->next_;
00165                 ReassemblyQueue::deleteseginfo(p);
00166         }
00167         tail_ = NULL;
00168         total_ = 0;
00169         return;
00170 }
00171 
00172 /*
00173  * clear out reassembly queue (and stack) up
00174  * to the given sequence number
00175  */
00176 
00177 TcpFlag
00178 ReassemblyQueue::clearto(TcpSeq seq)
00179 {
00180         TcpFlag flag = 0;
00181         seginfo *p = head_, *q;
00182         while (p) {
00183                 if (p->endseq_ <= seq) {
00184                         q = p->next_;
00185                         flag |= p->pflags_;
00186                         total_ -= (p->endseq_ - p->startseq_);
00187                         sremove(p);
00188                         fremove(p);
00189                         ReassemblyQueue::deleteseginfo(p);
00190                         p = q;
00191                 } else
00192                         break;
00193         }
00194         /* we might be trimming in the middle */
00195         if (p && p->startseq_ <= seq && p->endseq_ > seq) {
00196                 total_ -= (seq - p->startseq_);
00197                 p->startseq_ = seq;
00198                 flag |= p->pflags_;
00199         }
00200         return flag;
00201 }
00202 
00203 /*
00204  * gensack() -- generate 'maxsblock' sack blocks (start/end seq pairs)
00205  * at specified address
00206  * returns the number of blocks written into the buffer specified
00207  *
00208  * According to RFC2018, a sack block contains:
00209  *      left edge of block (first seq # of the block)
00210  *      right edge of block (seq# immed. following last seq# of the block)
00211  */
00212 
00213 int
00214 ReassemblyQueue::gensack(int *sacks, int maxsblock)
00215 {
00216         seginfo *p = top_;
00217         int cnt = maxsblock;
00218 
00219         while (p && maxsblock) {
00220                 *sacks++ = p->startseq_;
00221                 *sacks++ = p->endseq_;
00222                 --maxsblock;
00223                 p = p->snext_;
00224         }
00225         return (cnt - maxsblock);
00226 }
00227 
00228 /*
00229  * dumplist -- print out FIFO and LIFO (for debugging)
00230  */
00231 
00232 void
00233 ReassemblyQueue::dumplist()
00234 {
00235 
00236         printf("FIFO [size:%d]: ", total_);
00237         if (head_ == NULL) {
00238                 printf("NULL\n");
00239         } else {
00240                 register seginfo* p = head_;
00241                 while (p != NULL) {
00242                         if (p->rqflags_ & RQF_MARK) {
00243                                 printf("OOPS: LOOP1\n");
00244                                 abort();
00245                         }
00246                         printf("[->%d, %d<-<f:0x%x,c:%d>]",
00247                                 p->startseq_, p->endseq_, p->pflags_, p->cnt_);
00248                         p->rqflags_ |= RQF_MARK;
00249                         p = p->next_;
00250                 }
00251                 printf("\n");
00252                 p = tail_;
00253                 while (p != NULL) {
00254                         printf("[->%d, %d<-]",
00255                                 p->startseq_, p->endseq_);
00256                         p = p->prev_;
00257                 }
00258                 printf("\n");
00259         }
00260 
00261         printf("LIFO: ");
00262         if (top_ == NULL) {
00263                 printf("NULL\n");
00264         } else {
00265                 register seginfo* s = top_;
00266                 while (s != NULL) {
00267                         if (s->rqflags_ & RQF_MARK)
00268                                 s->rqflags_ &= ~RQF_MARK;
00269                         else {
00270                                 printf("OOPS: LOOP2\n");
00271                                 abort();
00272                         }
00273                         printf("[->%d, %d<-]",
00274                                 s->startseq_, s->endseq_);
00275                         s = s->snext_;
00276                 }
00277                 printf("\n");
00278                 s = bottom_;
00279                 while (s != NULL) {
00280                         printf("[->%d, %d<-]",
00281                                 s->startseq_, s->endseq_);
00282                         s = s->sprev_;
00283                 }
00284                 printf("\n");
00285         }
00286         printf("RCVNXT: %d\n", rcv_nxt_);
00287         printf("\n");
00288         fflush(stdout);
00289 }
00290 
00291 /*
00292  *
00293  * add() -- add a segment to the reassembly queue
00294  *      this is where the real action is...
00295  *      add the segment to both the LIFO and FIFO
00296  *
00297  * returns the aggregate header flags covering the block
00298  * just inserted (for historical reasons)
00299  *
00300  * add start/end seq to reassembly queue
00301  * start specifies starting seq# for segment, end specifies
00302  * last seq# number in the segment plus one
00303  */
00304 
00305 TcpFlag
00306 ReassemblyQueue::add(TcpSeq start, TcpSeq end, TcpFlag tiflags, RqFlag rqflags)
00307 {
00308 
00309         int needmerge = FALSE;
00310         int altered = FALSE;
00311         int initcnt = 1;        // initial value of cnt_ for new blk
00312 
00313         if (end < start) {
00314                 fprintf(stderr, "ReassemblyQueue::add() - end(%d) before start(%d)\n",
00315                         end, start);
00316                 abort();
00317         }
00318 
00319         if (head_ == NULL) {
00320                 if (top_ != NULL) {
00321                         fprintf(stderr, "ReassemblyQueue::add() - problem: FIFO empty, LIFO not\n");
00322                         abort();
00323                 }
00324 
00325                 // nobody there, just insert this one
00326 
00327 
00328                 tail_ = head_ = top_ = bottom_ =  ReassemblyQueue::newseginfo();
00329                 head_->prev_ = head_->next_ = head_->snext_ = head_->sprev_ = NULL;
00330                 head_->startseq_ = start;
00331                 head_->endseq_ = end;
00332                 head_->pflags_ = tiflags;
00333                 head_->rqflags_ = rqflags;
00334                 head_->cnt_ = initcnt;
00335 
00336                 total_ = (end - start);
00337 
00338                 //
00339                 // this shouldn't really happen, but
00340                 // do the right thing just in case
00341                 if (rcv_nxt_ >= start)
00342                         rcv_nxt_ = end;
00343 
00344                 return (tiflags);
00345         } else {
00346 
00347 again2:
00348                 seginfo *p = NULL, *q = NULL, *n, *r;
00349 
00350                 //
00351                 // in the code below, arrange for:
00352                 // q: points to segment after this one
00353                 // p: points to segment before this one
00354                 //
00355 
00356                 if (start >= tail_->endseq_) {
00357                         // at tail, no overlap
00358                         p = tail_;
00359                         if (start == tail_->endseq_)
00360                                 needmerge = TRUE;
00361                         goto endfast;
00362                 }
00363 
00364                 if (end <= head_->startseq_) {
00365                         // at head, no overlap
00366                         q = head_;
00367                         if (end == head_->startseq_)
00368                                 needmerge = TRUE;
00369                         goto endfast;
00370                 }
00371 
00372                 //
00373                 // search for segments before and after
00374                 // the new one; could be overlapped
00375                 //
00376                 q = head_;
00377                 while (q && q->startseq_ < end)
00378                         q = q->next_;
00379 
00380                 p = tail_;
00381                 while (p && p->endseq_ > start)
00382                         p = p->prev_;
00383 
00384 #ifdef notdef
00385 printf("Thinking of merging (s:%d, e:%d), p:%p (%d,%d), q:%p (%d,%d) into: \n",
00386 start, end, p, q,
00387         p ? p->startseq_ : 0,
00388         p ? p->endseq_ : 0,
00389         q ? n->startseq_ : 0,
00390         q ? n->endseq_ : 0);
00391 #endif
00392 
00393 
00394                 //
00395                 // kill anything that is completely overlapped
00396                 //
00397                 r = p ? p : head_;
00398                 while (r && r != q)  {
00399                         if (start == r->startseq_ && end == r->endseq_) {
00400                                 // exact overlap
00401                                 r->pflags_ |= tiflags;
00402                                 if (RQC_CNTDUPS == TRUE)
00403                                         r->cnt_++;
00404                                 return (r->pflags_);
00405                         } else if (start <= r->startseq_ && end >= r->endseq_) {
00406                                 // complete overlap, not exact
00407                                 total_ -= (r->endseq_ - r->startseq_);
00408                                 n = r;
00409                                 r = r->next_;
00410                                 tiflags |= n->pflags_;
00411                                 initcnt += n->cnt_;
00412                                 fremove(n);
00413                                 sremove(n);
00414                                 ReassemblyQueue::deleteseginfo(n);
00415                                 altered = TRUE;
00416                         } else
00417                                 r = r->next_;
00418                 }
00419 
00420 
00421                 //
00422                 // if we completely overlapped everything, the list
00423                 // will now be empty.  In this case, just add the new one
00425 
00426                 if (empty())
00427                         goto endfast;
00428 
00429                 if (altered) {
00430                         altered = FALSE;
00431                         goto again2;
00432                 }
00433 
00434                 // look for left-side merge
00435                 // update existing seg's start seq with new start
00436                 if (p == NULL || p->next_->startseq_ < start) {
00437                         if (p == NULL)
00438                                 p = head_;
00439                         else
00440                                 p = p->next_;
00441                                 
00442                         if (start < p->startseq_) {
00443                                 total_ += (p->startseq_ - start);
00444                                 p->startseq_ = start;
00445                         }
00446                         start = p->endseq_;
00447                         needmerge = TRUE;
00448                         p->pflags_ |= tiflags;
00449                         p->cnt_++;
00450                         --initcnt;
00451                 }
00452 
00453                 // look for right-side merge
00454                 // update existing seg's end seq with new end
00455                 if (q == NULL || q->prev_->endseq_ > end) {
00456                         if (q == NULL)
00457                                 q = tail_;
00458                         else
00459                                 q = q->prev_;
00460 
00461                         if (end > q->endseq_) {
00462                                 total_ += (end - q->endseq_);
00463                                 q->endseq_ = end;
00464                         }
00465                         end = q->startseq_;
00466                         needmerge = TRUE;
00467                         q->pflags_ |= tiflags;
00468                         if (!needmerge) {
00469                                 // if needmerge is TRUE, that can
00470                                 // only be the case if we did a left-side
00471                                 // merge (above), which has already taken
00472                                 // accounting of the new segment
00473                                 q->cnt_++;
00474                                 --initcnt;
00475                         }
00476                 }
00477 
00478 
00479                 if (end <= start) {
00480                         if (rcv_nxt_ >= head_->startseq_)
00481                                 rcv_nxt_ = head_->endseq_;
00482                         return (tiflags);
00483                 }
00484                         
00485 
00486                 //
00487                 // if p & q are adjacent and new one
00488                 // fits between, that is an easy case
00489                 //
00490 
00491                 if (!needmerge && p->next_ == q && p->endseq_ <= start && q->startseq_ >= end) {
00492                         if (p->endseq_ == start || q->startseq_ == end)
00493                                 needmerge = TRUE;
00494                 }
00495 
00496 endfast:
00497                 n = ReassemblyQueue::newseginfo();
00498                 n->startseq_ = start;
00499                 n->endseq_ = end;
00500                 n->pflags_ = tiflags;
00501                 n->rqflags_ = rqflags;
00502                 n->cnt_=  initcnt;
00503 
00504                 n->prev_ = p;
00505                 n->next_ = q;
00506 
00507                 push(n);
00508 
00509                 if (p)
00510                         p->next_ = n;
00511                 else
00512                         head_ = n;
00513 
00514                 if (q)
00515                         q->prev_ = n;
00516                 else
00517                         tail_ = n;
00518 
00519 
00520                 //
00521                 // If there is an adjacency condition,
00522                 // call coalesce to deal with it.
00523                 // If not, there is a chance we inserted
00524                 // at the head at the rcv_nxt_ point.  In
00525                 // this case we ned to update rcv_nxt_ to
00526                 // the end of the newly-inserted segment
00527                 //
00528 
00529                 total_ += (end - start);
00530 
00531                 if (needmerge)
00532                         return(coalesce(p, n, q));
00533                 else if (rcv_nxt_ >= start) {
00534                         rcv_nxt_ = end;
00535                 }
00536 
00537                 return tiflags;
00538         }
00539 }
00540 /*
00541  * We need to see if we can coalesce together the
00542  * blocks in and around the new block
00543  *
00544  * Assumes p is prev, n is new, p is after
00545  */
00546 TcpFlag
00547 ReassemblyQueue::coalesce(seginfo *p, seginfo *n, seginfo *q)
00548 {
00549         TcpFlag flags = 0;
00550 
00551 #ifdef RQDEBUG
00552 printf("coalesce(%p,%p,%p)\n", p, n, q);
00553 printf(" [(%d,%d),%d],[(%d,%d),%d],[(%d,%d),%d]\n",
00554         p ? p->startseq_ : 0,
00555         p ? p->endseq_ : 0,
00556         p ? p->cnt_ : -1000,
00557         n ? n->startseq_ : 0,
00558         n ? n->endseq_ : 0,
00559         n ? n->cnt_ : -1000,
00560         q ? n->startseq_ : 0,
00561         q ? n->endseq_ : 0,
00562         q ? n->cnt_ : -1000);
00563 dumplist();
00564 #endif
00565 
00566         if (p && q && p->endseq_ == n->startseq_ && n->endseq_ == q->startseq_) {
00567                 // new block fills hole between p and q
00568                 // delete the new block and the block after, update p
00569                 sremove(n);
00570                 fremove(n);
00571                 sremove(q);
00572                 fremove(q);
00573                 p->endseq_ = q->endseq_;
00574                 p->cnt_ += (n->cnt_ + q->cnt_);
00575                 flags = (p->pflags_ |= n->pflags_);
00576                 ReassemblyQueue::deleteseginfo(n);
00577                 ReassemblyQueue::deleteseginfo(q);
00578         } else if (p && (p->endseq_ == n->startseq_)) {
00579                 // new block joins p, but not q
00580                 // update p with n's seq data, delete new block
00581                 sremove(n);
00582                 fremove(n);
00583                 p->endseq_ = n->endseq_;
00584                 flags = (p->pflags_ |= n->pflags_);
00585                 p->cnt_ += n->cnt_;
00586                 ReassemblyQueue::deleteseginfo(n);
00587         } else if (q && (n->endseq_ == q->startseq_)) {
00588                 // new block joins q, but not p
00589                 // update q with n's seq data, delete new block
00590                 sremove(n);
00591                 fremove(n);
00592                 q->startseq_ = n->startseq_;
00593                 flags = (q->pflags_ |= n->pflags_);
00594                 q->cnt_ += n->cnt_;
00595                 ReassemblyQueue::deleteseginfo(n);
00596                 p = q;  // ensure p points to something
00597         }
00598 
00599         //
00600         // at this point, p points to the updated/coalesced
00601         // block.  If it advances the highest in-seq value,
00602         // update rcv_nxt_ appropriately
00603         //
00604         if (rcv_nxt_ >= p->startseq_)
00605                 rcv_nxt_ = p->endseq_;
00606         return (flags);
00607 }
00608 
00609 /*
00610  * look for the next hole, starting with the given
00611  * sequence number.  If this seq number is contained in
00612  * a SACK block we have, return the ending sequence number
00613  * of the block.  Also, fill in the nxtcnt and nxtbytes fields
00614  * with the number and sum total size of the sack regions above
00615  * the block.
00616  */
00617 int
00618 ReassemblyQueue::nexthole(TcpSeq seq, int& nxtcnt, int& nxtbytes)
00619 {
00620 
00621         nxtbytes = nxtcnt = -1;
00622         hint_ = head_;
00623 
00624         seginfo* p;
00625         for (p = hint_; p; p = p->next_) {
00626                 // seq# is prior to SACK region
00627                 // so seq# is a legit hole
00628                 if (p->startseq_ > seq) {
00629                         cnts(p, nxtcnt, nxtbytes);
00630                         return (seq);
00631                 }
00632 
00633                 // seq# is covered by SACK region
00634                 // so the hole is at the end of the region
00635                 if ((p->startseq_ <= seq) && (p->endseq_ >= seq)) {
00636                         if (p->next_) {
00637                                 cnts(p->next_, nxtcnt, nxtbytes);
00638                         }
00639                         return (p->endseq_);
00640                 }
00641         }
00642         return (-1);
00643 }
00644 
00645 
00646 #ifdef RQDEBUG
00647 main()
00648 {
00649         int rcvnxt = 1;
00650         ReassemblyQueue rq(rcvnxt);
00651 
00652         static int blockstore[64];
00653         int *blocks = blockstore;
00654         int nblocks = 5;
00655         int i;
00656 
00657         printf("Simple---\n");
00658         rq.add(2, 4, 0, 0);
00659         rq.add(6, 8, 0, 0);     // disc
00660         printf("D1\n");
00661         rq.dumplist();  // [(2,4),1], [(6,8),1]
00662 
00663         rq.add(1,2, 0, 0);      // l merge
00664         printf("D2\n");
00665         rq.dumplist();  // [(1,4),2], [(6,8),1]
00666 
00667         rq.add(8, 10, 0, 00);   // r merge
00668         printf("D3\n");
00669         rq.dumplist();  // [(1,4),2], [(6, 10),2]
00670 
00671         rq.add(4, 6, 0, 0);     // m merge
00672         printf("Simple output:\n");
00673         rq.dumplist();  // [(1, 10),5]
00674 
00675         printf("X0:\n");
00676         rq.init(1);
00677         rq.add(5,10, 0, 0);
00678         rq.add(11,20, 0, 0);
00679         rq.add(5,10, 0, 0);     // dup left
00680         rq.dumplist();  // [(5,10),1], [(11,20),1]
00681 
00682         printf("X1:\n");
00683         rq.init(1);
00684         rq.add(5,10, 0, 0);
00685         rq.add(11,20, 0, 0);
00686         rq.add(11,20, 0, 0);    // dup rt
00687         rq.dumplist();  // [(5,10),1], [(11,20),1]
00688 
00689         printf("X2:\n");
00690         rq.init(1);
00691         rq.add(5,10, 0, 0);
00692         rq.add(11,20, 0, 0);
00693         rq.add(30, 40, 0, 0);
00694         rq.add(11,20, 0, 0);    // dup mid
00695         rq.dumplist();  // [(5,10),1], [(11,20),1], [(30,40),1]
00696 
00697         printf("X3\n");
00698         rq.add(30,50,0,0);      // dup rt
00699         rq.dumplist();  // [(5,10),1], [(11,20),1], [(30,50),2]
00700 
00701         printf("X4\n");
00702         rq.add(1,10,0,0);       // dup lt
00703         rq.dumplist();  // [(1,10),2], [(11,20),1], [(30,50),2]
00704 
00705         printf("C1:\n");
00706         rq.init(1);
00707         rq.add(2, 4, 0, 0);
00708         rq.add(1, 4, 0, 0);     // l overlap full
00709         rq.dumplist();  // [(1,4),2]
00710 
00711         printf("C2:\n");
00712         rq.init(1);
00713         rq.add(2, 4, 0, 0);
00714         rq.add(1, 3, 0, 0);     // l overlap part
00715         rq.dumplist();  // [(1,4),2]
00716 
00717         printf("C3:\n");
00718         rq.init(1);
00719         rq.add(2, 4, 0, 0);
00720         rq.add(2, 7, 0, 0);     // r overlap full
00721         rq.dumplist();  // [(2,7),2]
00722 
00723         printf("C4:\n");
00724         rq.init(1);
00725         rq.add(2, 4, 0, 0);
00726         rq.add(3, 7, 0, 0);     // r overlap part
00727         rq.dumplist();  // [(2,7),2]
00728 
00729         printf("C5:\n");
00730         rq.init(1);
00731         rq.add(2, 4, 0, 0);
00732         rq.add(6, 8, 0, 0);
00733         rq.add(1, 9, 0, 0);     // double olap - ends
00734         rq.dumplist();  // [(1,9),3]
00735 
00736         printf("C6:\n");
00737         rq.init(1);
00738         rq.add(2, 4, 0, 0);
00739         rq.add(6, 8, 0, 0);
00740         rq.add(15, 20, 0, 0);
00741         rq.dumplist();  // [(2,4),1], [(6,8),1], [(15,20),1]
00742         rq.add(5, 9, 0, 0);     // overlap middle
00743         rq.dumplist();  // [(2,4),1], [(5,9),2], [(15,20),1]
00744 
00745         printf("C7:\n");
00746         rq.init(1);
00747         rq.add(1, 2, 0, 0);
00748         rq.add(3, 5, 0, 0);
00749         rq.add(6, 8, 0, 0);
00750         rq.add(9, 10, 0, 0);
00751         rq.dumplist();  // [(1,2),1],[(3,5),1],[(6,8),1],[(9,10),1]
00752         rq.add(4, 7, 0, 0);     // double olap middle
00753         rq.dumplist();  // [(1,2),1], [(3,8),3], [(9,10),1]
00754 
00755         printf("C8:\n");
00756         rq.init(1);
00757         rq.add(1, 2, 0, 0);
00758         rq.add(3, 5, 0, 0);
00759         rq.add(10, 12, 0, 0);
00760         rq.add(20, 30, 0, 0);
00761         rq.dumplist();  // [(1,2),1], [(3,5),1], [(10,12),1], [(20,30),1]
00762         rq.add(4, 8, 0, 0);     // single olap middle
00763         rq.dumplist();  // [(1,2),1], [(3,8),2], [(10,12),1], [(20,30),1]
00764 
00765         rq.init(1);
00766         rq.add(1, 5, 0, 0);
00767         rq.add(10, 20, 0, 0);
00768         //rq.add(40321, 41281, 0, 0);
00769         //rq.add(42241, 43201, 0, 0);
00770         //rq.add(44161, 45121, 0, 0);
00771         rq.dumplist();  // [(1,5),1], [(10,20),1]
00772         //rq.add(40321, 41281, 0, 0);
00773         rq.add(1, 5, 0, 0);
00774         rq.dumplist();  // [(1,5),1], [(10,20),1]
00775 
00776         int x, y;
00777         printf("NH1: %d\n", rq.nexthole(3, x, y));
00778         printf("NH2: %d\n", rq.nexthole(5, x, y));
00779         printf("CLR to 4\n");
00780         rq.clearto(4);
00781         rq.dumplist();
00782 
00783         exit(0);
00784 }
00785 #endif
00786 

Generated on Tue Apr 20 12:14:30 2004 for NS2.26SourcesOriginal by doxygen 1.3.3