rq.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:17k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) Intel Corporation 2001. All rights reserved.
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *   http://www.apache.org/licenses/LICENSE-2.0
  8.  *
  9.  * Unless required by applicable law or agreed to in writing, software
  10.  * distributed under the License is distributed on an "AS IS" BASIS,
  11.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12.  * See the License for the specific language governing permissions and
  13.  * limitations under the License.
  14. */
  15. /*
  16.  * Copyright (c) 1991-1997 Regents of the University of California.
  17.  * All rights reserved.
  18.  *
  19.  * Redistribution and use in source and binary forms, with or without
  20.  * modification, are permitted provided that the following conditions
  21.  * are met:
  22.  * 1. Redistributions of source code must retain the above copyright
  23.  *    notice, this list of conditions and the following disclaimer.
  24.  * 2. Redistributions in binary form must reproduce the above copyright
  25.  *    notice, this list of conditions and the following disclaimer in the
  26.  *    documentation and/or other materials provided with the distribution.
  27.  * 3. All advertising materials mentioning features or use of this software
  28.  *    must display the following acknowledgement:
  29.  * This product includes software developed by the Computer Systems
  30.  * Engineering Group at Lawrence Berkeley Laboratory.
  31.  * 4. Neither the name of the University nor of the Laboratory may be used
  32.  *    to endorse or promote products derived from this software without
  33.  *    specific prior written permission.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  36.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  38.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  39.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  40.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  41.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  42.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  43.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  44.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  45.  * SUCH DAMAGE.
  46.  *
  47.  */
  48. #include "rq.h"
  49. ReassemblyQueue::seginfo* ReassemblyQueue::freelist_ = NULL;
  50. ReassemblyQueue::seginfo* ReassemblyQueue::newseginfo()
  51. {
  52. seginfo *s;
  53. if( (s = freelist_) ){
  54. freelist_ = s->next_;
  55. return s;
  56. }else{
  57. return new seginfo;
  58. }
  59. }
  60. void ReassemblyQueue::deleteseginfo(ReassemblyQueue::seginfo* s)
  61. {
  62. s->next_ = freelist_;
  63. freelist_ = s;
  64. }
  65. /*
  66.  * unlink a seginfo from its FIFO
  67.  */
  68. void
  69. ReassemblyQueue::fremove(seginfo* p)
  70. {
  71. if (hint_ == p)
  72. hint_ = NULL;
  73. if (p->prev_)
  74. p->prev_->next_ = p->next_;
  75. else
  76. head_ = p->next_;
  77. if (p->next_)
  78. p->next_->prev_ = p->prev_;
  79. else
  80. tail_ = p->prev_;
  81. }
  82. /*
  83.  * unlink a seginfo from its LIFO
  84.  */
  85. void
  86. ReassemblyQueue::sremove(seginfo* p)
  87. {
  88. if (hint_ == p)
  89. hint_ = NULL;
  90. if (p->sprev_)
  91. p->sprev_->snext_ = p->snext_;
  92. else
  93. top_ = p->snext_;
  94. if (p->snext_)
  95. p->snext_->sprev_ = p->sprev_;
  96. else
  97. bottom_ = p->sprev_;
  98. }
  99. /*
  100.  * push a seginfo on the LIFO
  101.  */
  102. void
  103. ReassemblyQueue::push(seginfo *p)
  104. {
  105. p->snext_ = top_;
  106. p->sprev_ = NULL;
  107. top_ = p;
  108. if (p->snext_)
  109. p->snext_->sprev_ = p;
  110. else
  111. bottom_ = p;
  112. }
  113. /*
  114.  * counts: return the # of blks and byte counts in
  115.  * them starting at the given node
  116.  */
  117. void
  118. ReassemblyQueue::cnts(seginfo *p, int& blkcnt, int& bytecnt)
  119. {
  120. int blks = 0;
  121. int bytes = 0;
  122. while (p != NULL) {
  123. ++blks;
  124. bytes += (p->endseq_ - p->startseq_);
  125. p = p->next_;
  126. }
  127. blkcnt = blks;
  128. bytecnt = bytes;
  129. return;
  130. }
  131. /*
  132.  * clear out reassembly queue and stack
  133.  */
  134. void
  135. ReassemblyQueue::clear()
  136. {
  137. // clear stack and end of queue
  138. tail_ = top_ = bottom_ = hint_ = NULL;
  139. seginfo *p = head_;
  140. while (head_) {
  141. p = head_;
  142. head_= head_->next_;
  143. ReassemblyQueue::deleteseginfo(p);
  144. }
  145. tail_ = NULL;
  146. total_ = 0;
  147. return;
  148. }
  149. /*
  150.  * clear out reassembly queue (and stack) up
  151.  * to the given sequence number
  152.  */
  153. TcpFlag
  154. ReassemblyQueue::clearto(TcpSeq seq)
  155. {
  156. TcpFlag flag = 0;
  157. seginfo *p = head_, *q;
  158. while (p) {
  159. if (p->endseq_ <= seq) {
  160. q = p->next_;
  161. flag |= p->pflags_;
  162. total_ -= (p->endseq_ - p->startseq_);
  163. sremove(p);
  164. fremove(p);
  165. ReassemblyQueue::deleteseginfo(p);
  166. p = q;
  167. } else
  168. break;
  169. }
  170. /* we might be trimming in the middle */
  171. if (p && p->startseq_ <= seq && p->endseq_ > seq) {
  172. total_ -= (seq - p->startseq_);
  173. p->startseq_ = seq;
  174. flag |= p->pflags_;
  175. }
  176. return flag;
  177. }
  178. /*
  179.  * gensack() -- generate 'maxsblock' sack blocks (start/end seq pairs)
  180.  * at specified address
  181.  * returns the number of blocks written into the buffer specified
  182.  *
  183.  * According to RFC2018, a sack block contains:
  184.  * left edge of block (first seq # of the block)
  185.  * right edge of block (seq# immed. following last seq# of the block)
  186.  */
  187. int
  188. ReassemblyQueue::gensack(int *sacks, int maxsblock)
  189. {
  190. seginfo *p = top_;
  191. int cnt = maxsblock;
  192. while (p && maxsblock) {
  193. *sacks++ = p->startseq_;
  194. *sacks++ = p->endseq_;
  195. --maxsblock;
  196. p = p->snext_;
  197. }
  198. return (cnt - maxsblock);
  199. }
  200. /*
  201.  * dumplist -- print out FIFO and LIFO (for debugging)
  202.  */
  203. void
  204. ReassemblyQueue::dumplist()
  205. {
  206. printf("FIFO [size:%d]: ", total_);
  207. if (head_ == NULL) {
  208. printf("NULLn");
  209. } else {
  210. register seginfo* p = head_;
  211. while (p != NULL) {
  212. if (p->rqflags_ & RQF_MARK) {
  213. printf("OOPS: LOOP1n");
  214. abort();
  215. }
  216. printf("[->%d, %d<-<f:0x%x,c:%d>]",
  217. p->startseq_, p->endseq_, p->pflags_, p->cnt_);
  218. p->rqflags_ |= RQF_MARK;
  219. p = p->next_;
  220. }
  221. printf("n");
  222. p = tail_;
  223. while (p != NULL) {
  224. printf("[->%d, %d<-]",
  225. p->startseq_, p->endseq_);
  226. p = p->prev_;
  227. }
  228. printf("n");
  229. }
  230. printf("LIFO: ");
  231. if (top_ == NULL) {
  232. printf("NULLn");
  233. } else {
  234. register seginfo* s = top_;
  235. while (s != NULL) {
  236. if (s->rqflags_ & RQF_MARK)
  237. s->rqflags_ &= ~RQF_MARK;
  238. else {
  239. printf("OOPS: LOOP2n");
  240. abort();
  241. }
  242. printf("[->%d, %d<-]",
  243. s->startseq_, s->endseq_);
  244. s = s->snext_;
  245. }
  246. printf("n");
  247. s = bottom_;
  248. while (s != NULL) {
  249. printf("[->%d, %d<-]",
  250. s->startseq_, s->endseq_);
  251. s = s->sprev_;
  252. }
  253. printf("n");
  254. }
  255. printf("RCVNXT: %dn", rcv_nxt_);
  256. printf("n");
  257. fflush(stdout);
  258. }
  259. /*
  260.  *
  261.  * add() -- add a segment to the reassembly queue
  262.  * this is where the real action is...
  263.  * add the segment to both the LIFO and FIFO
  264.  *
  265.  * returns the aggregate header flags covering the block
  266.  * just inserted (for historical reasons)
  267.  *
  268.  * add start/end seq to reassembly queue
  269.  * start specifies starting seq# for segment, end specifies
  270.  * last seq# number in the segment plus one
  271.  */
  272. TcpFlag
  273. ReassemblyQueue::add(TcpSeq start, TcpSeq end, TcpFlag tiflags, RqFlag rqflags)
  274. {
  275. int needmerge = FALSE;
  276. int altered = FALSE;
  277. int initcnt = 1; // initial value of cnt_ for new blk
  278. if (end < start) {
  279. fprintf(stderr, "ReassemblyQueue::add() - end(%d) before start(%d)n",
  280. end, start);
  281. abort();
  282. }
  283. if (head_ == NULL) {
  284. if (top_ != NULL) {
  285. fprintf(stderr, "ReassemblyQueue::add() - problem: FIFO empty, LIFO notn");
  286. abort();
  287. }
  288. // nobody there, just insert this one
  289. tail_ = head_ = top_ = bottom_ =  ReassemblyQueue::newseginfo();
  290. head_->prev_ = head_->next_ = head_->snext_ = head_->sprev_ = NULL;
  291. head_->startseq_ = start;
  292. head_->endseq_ = end;
  293. head_->pflags_ = tiflags;
  294. head_->rqflags_ = rqflags;
  295. head_->cnt_ = initcnt;
  296. total_ = (end - start);
  297. //
  298. // this shouldn't really happen, but
  299. // do the right thing just in case
  300. if (rcv_nxt_ >= start)
  301. rcv_nxt_ = end;
  302. return (tiflags);
  303. } else {
  304. again2:
  305. seginfo *p = NULL, *q = NULL, *n, *r;
  306. //
  307. // in the code below, arrange for:
  308. // q: points to segment after this one
  309. // p: points to segment before this one
  310. //
  311. if (start >= tail_->endseq_) {
  312. // at tail, no overlap
  313. p = tail_;
  314. if (start == tail_->endseq_)
  315. needmerge = TRUE;
  316. goto endfast;
  317. }
  318. if (end <= head_->startseq_) {
  319. // at head, no overlap
  320. q = head_;
  321. if (end == head_->startseq_)
  322. needmerge = TRUE;
  323. goto endfast;
  324. }
  325. //
  326. // search for segments before and after
  327. // the new one; could be overlapped
  328. //
  329. q = head_;
  330. while (q && q->startseq_ < end)
  331. q = q->next_;
  332. p = tail_;
  333. while (p && p->endseq_ > start)
  334. p = p->prev_;
  335. #ifdef notdef
  336. printf("Thinking of merging (s:%d, e:%d), p:%p (%d,%d), q:%p (%d,%d) into: n",
  337. start, end, p, q,
  338. p ? p->startseq_ : 0,
  339. p ? p->endseq_ : 0,
  340. q ? n->startseq_ : 0,
  341. q ? n->endseq_ : 0);
  342. #endif
  343. //
  344. // kill anything that is completely overlapped
  345. //
  346. r = p ? p : head_;
  347. while (r && r != q)  {
  348. if (start == r->startseq_ && end == r->endseq_) {
  349. // exact overlap
  350. r->pflags_ |= tiflags;
  351. if (RQC_CNTDUPS == TRUE)
  352. r->cnt_++;
  353. return (r->pflags_);
  354. } else if (start <= r->startseq_ && end >= r->endseq_) {
  355. // complete overlap, not exact
  356. total_ -= (r->endseq_ - r->startseq_);
  357. n = r;
  358. r = r->next_;
  359. tiflags |= n->pflags_;
  360. initcnt += n->cnt_;
  361. fremove(n);
  362. sremove(n);
  363. ReassemblyQueue::deleteseginfo(n);
  364. altered = TRUE;
  365. } else
  366. r = r->next_;
  367. }
  368. //
  369. // if we completely overlapped everything, the list
  370. // will now be empty.  In this case, just add the new one
  371. ///
  372. if (empty())
  373. goto endfast;
  374. if (altered) {
  375. altered = FALSE;
  376. goto again2;
  377. }
  378. // look for left-side merge
  379. // update existing seg's start seq with new start
  380. if (p == NULL || p->next_->startseq_ < start) {
  381. if (p == NULL)
  382. p = head_;
  383. else
  384. p = p->next_;
  385. if (start < p->startseq_) {
  386. total_ += (p->startseq_ - start);
  387. p->startseq_ = start;
  388. }
  389. start = p->endseq_;
  390. needmerge = TRUE;
  391. p->pflags_ |= tiflags;
  392. p->cnt_++;
  393. --initcnt;
  394. }
  395. // look for right-side merge
  396. // update existing seg's end seq with new end
  397. if (q == NULL || q->prev_->endseq_ > end) {
  398. if (q == NULL)
  399. q = tail_;
  400. else
  401. q = q->prev_;
  402. if (end > q->endseq_) {
  403. total_ += (end - q->endseq_);
  404. q->endseq_ = end;
  405. }
  406. end = q->startseq_;
  407. needmerge = TRUE;
  408. q->pflags_ |= tiflags;
  409. if (!needmerge) {
  410. // if needmerge is TRUE, that can
  411. // only be the case if we did a left-side
  412. // merge (above), which has already taken
  413. // accounting of the new segment
  414. q->cnt_++;
  415. --initcnt;
  416. }
  417. }
  418. if (end <= start) {
  419. if (rcv_nxt_ >= head_->startseq_)
  420. rcv_nxt_ = head_->endseq_;
  421. return (tiflags);
  422. }
  423. //
  424. // if p & q are adjacent and new one
  425. // fits between, that is an easy case
  426. //
  427. if (!needmerge && p->next_ == q && p->endseq_ <= start && q->startseq_ >= end) {
  428. if (p->endseq_ == start || q->startseq_ == end)
  429. needmerge = TRUE;
  430. }
  431. endfast:
  432. n = ReassemblyQueue::newseginfo();
  433. n->startseq_ = start;
  434. n->endseq_ = end;
  435. n->pflags_ = tiflags;
  436. n->rqflags_ = rqflags;
  437. n->cnt_=  initcnt;
  438. n->prev_ = p;
  439. n->next_ = q;
  440. push(n);
  441. if (p)
  442. p->next_ = n;
  443. else
  444. head_ = n;
  445. if (q)
  446. q->prev_ = n;
  447. else
  448. tail_ = n;
  449. //
  450. // If there is an adjacency condition,
  451. // call coalesce to deal with it.
  452. // If not, there is a chance we inserted
  453. // at the head at the rcv_nxt_ point.  In
  454. // this case we ned to update rcv_nxt_ to
  455. // the end of the newly-inserted segment
  456. //
  457. total_ += (end - start);
  458. if (needmerge)
  459. return(coalesce(p, n, q));
  460. else if (rcv_nxt_ >= start) {
  461. rcv_nxt_ = end;
  462. }
  463. return tiflags;
  464. }
  465. }
  466. /*
  467.  * We need to see if we can coalesce together the
  468.  * blocks in and around the new block
  469.  *
  470.  * Assumes p is prev, n is new, p is after
  471.  */
  472. TcpFlag
  473. ReassemblyQueue::coalesce(seginfo *p, seginfo *n, seginfo *q)
  474. {
  475. TcpFlag flags = 0;
  476. #ifdef RQDEBUG
  477. printf("coalesce(%p,%p,%p)n", p, n, q);
  478. printf(" [(%d,%d),%d],[(%d,%d),%d],[(%d,%d),%d]n",
  479. p ? p->startseq_ : 0,
  480. p ? p->endseq_ : 0,
  481. p ? p->cnt_ : -1000,
  482. n ? n->startseq_ : 0,
  483. n ? n->endseq_ : 0,
  484. n ? n->cnt_ : -1000,
  485. q ? n->startseq_ : 0,
  486. q ? n->endseq_ : 0,
  487. q ? n->cnt_ : -1000);
  488. dumplist();
  489. #endif
  490. if (p && q && p->endseq_ == n->startseq_ && n->endseq_ == q->startseq_) {
  491. // new block fills hole between p and q
  492. // delete the new block and the block after, update p
  493. sremove(n);
  494. fremove(n);
  495. sremove(q);
  496. fremove(q);
  497. p->endseq_ = q->endseq_;
  498. p->cnt_ += (n->cnt_ + q->cnt_);
  499. flags = (p->pflags_ |= n->pflags_);
  500. ReassemblyQueue::deleteseginfo(n);
  501. ReassemblyQueue::deleteseginfo(q);
  502. } else if (p && (p->endseq_ == n->startseq_)) {
  503. // new block joins p, but not q
  504. // update p with n's seq data, delete new block
  505. sremove(n);
  506. fremove(n);
  507. p->endseq_ = n->endseq_;
  508. flags = (p->pflags_ |= n->pflags_);
  509. p->cnt_ += n->cnt_;
  510. ReassemblyQueue::deleteseginfo(n);
  511. } else if (q && (n->endseq_ == q->startseq_)) {
  512. // new block joins q, but not p
  513. // update q with n's seq data, delete new block
  514. sremove(n);
  515. fremove(n);
  516. q->startseq_ = n->startseq_;
  517. flags = (q->pflags_ |= n->pflags_);
  518. q->cnt_ += n->cnt_;
  519. ReassemblyQueue::deleteseginfo(n);
  520. p = q; // ensure p points to something
  521. }
  522. //
  523. // at this point, p points to the updated/coalesced
  524. // block.  If it advances the highest in-seq value,
  525. // update rcv_nxt_ appropriately
  526. //
  527. if (rcv_nxt_ >= p->startseq_)
  528. rcv_nxt_ = p->endseq_;
  529. return (flags);
  530. }
  531. /*
  532.  * look for the next hole, starting with the given
  533.  * sequence number.  If this seq number is contained in
  534.  * a SACK block we have, return the ending sequence number
  535.  * of the block.  Also, fill in the nxtcnt and nxtbytes fields
  536.  * with the number and sum total size of the sack regions above
  537.  * the block.
  538.  */
  539. int
  540. ReassemblyQueue::nexthole(TcpSeq seq, int& nxtcnt, int& nxtbytes)
  541. {
  542. nxtbytes = nxtcnt = -1;
  543. hint_ = head_;
  544. seginfo* p;
  545. for (p = hint_; p; p = p->next_) {
  546. // seq# is prior to SACK region
  547. // so seq# is a legit hole
  548. if (p->startseq_ > seq) {
  549. cnts(p, nxtcnt, nxtbytes);
  550. return (seq);
  551. }
  552. // seq# is covered by SACK region
  553. // so the hole is at the end of the region
  554. if ((p->startseq_ <= seq) && (p->endseq_ >= seq)) {
  555. if (p->next_) {
  556. cnts(p->next_, nxtcnt, nxtbytes);
  557. }
  558. return (p->endseq_);
  559. }
  560. }
  561. return (-1);
  562. }
  563. #ifdef RQDEBUG
  564. main()
  565. {
  566. int rcvnxt = 1;
  567. ReassemblyQueue rq(rcvnxt);
  568. static int blockstore[64];
  569. int *blocks = blockstore;
  570. int nblocks = 5;
  571. int i;
  572. printf("Simple---n");
  573. rq.add(2, 4, 0, 0);
  574. rq.add(6, 8, 0, 0); // disc
  575. printf("D1n");
  576. rq.dumplist(); // [(2,4),1], [(6,8),1]
  577. rq.add(1,2, 0, 0); // l merge
  578. printf("D2n");
  579. rq.dumplist(); // [(1,4),2], [(6,8),1]
  580. rq.add(8, 10, 0, 00); // r merge
  581. printf("D3n");
  582. rq.dumplist(); // [(1,4),2], [(6, 10),2]
  583. rq.add(4, 6, 0, 0); // m merge
  584. printf("Simple output:n");
  585. rq.dumplist(); // [(1, 10),5]
  586. printf("X0:n");
  587. rq.init(1);
  588. rq.add(5,10, 0, 0);
  589. rq.add(11,20, 0, 0);
  590. rq.add(5,10, 0, 0); // dup left
  591. rq.dumplist(); // [(5,10),1], [(11,20),1]
  592. printf("X1:n");
  593. rq.init(1);
  594. rq.add(5,10, 0, 0);
  595. rq.add(11,20, 0, 0);
  596. rq.add(11,20, 0, 0); // dup rt
  597. rq.dumplist(); // [(5,10),1], [(11,20),1]
  598. printf("X2:n");
  599. rq.init(1);
  600. rq.add(5,10, 0, 0);
  601. rq.add(11,20, 0, 0);
  602. rq.add(30, 40, 0, 0);
  603. rq.add(11,20, 0, 0); // dup mid
  604. rq.dumplist(); // [(5,10),1], [(11,20),1], [(30,40),1]
  605. printf("X3n");
  606. rq.add(30,50,0,0); // dup rt
  607. rq.dumplist(); // [(5,10),1], [(11,20),1], [(30,50),2]
  608. printf("X4n");
  609. rq.add(1,10,0,0); // dup lt
  610. rq.dumplist(); // [(1,10),2], [(11,20),1], [(30,50),2]
  611. printf("C1:n");
  612. rq.init(1);
  613. rq.add(2, 4, 0, 0);
  614. rq.add(1, 4, 0, 0); // l overlap full
  615. rq.dumplist(); // [(1,4),2]
  616. printf("C2:n");
  617. rq.init(1);
  618. rq.add(2, 4, 0, 0);
  619. rq.add(1, 3, 0, 0); // l overlap part
  620. rq.dumplist(); // [(1,4),2]
  621. printf("C3:n");
  622. rq.init(1);
  623. rq.add(2, 4, 0, 0);
  624. rq.add(2, 7, 0, 0); // r overlap full
  625. rq.dumplist(); // [(2,7),2]
  626. printf("C4:n");
  627. rq.init(1);
  628. rq.add(2, 4, 0, 0);
  629. rq.add(3, 7, 0, 0); // r overlap part
  630. rq.dumplist(); // [(2,7),2]
  631. printf("C5:n");
  632. rq.init(1);
  633. rq.add(2, 4, 0, 0);
  634. rq.add(6, 8, 0, 0);
  635. rq.add(1, 9, 0, 0); // double olap - ends
  636. rq.dumplist(); // [(1,9),3]
  637. printf("C6:n");
  638. rq.init(1);
  639. rq.add(2, 4, 0, 0);
  640. rq.add(6, 8, 0, 0);
  641. rq.add(15, 20, 0, 0);
  642. rq.dumplist(); // [(2,4),1], [(6,8),1], [(15,20),1]
  643. rq.add(5, 9, 0, 0); // overlap middle
  644. rq.dumplist(); // [(2,4),1], [(5,9),2], [(15,20),1]
  645. printf("C7:n");
  646. rq.init(1);
  647. rq.add(1, 2, 0, 0);
  648. rq.add(3, 5, 0, 0);
  649. rq.add(6, 8, 0, 0);
  650. rq.add(9, 10, 0, 0);
  651. rq.dumplist(); // [(1,2),1],[(3,5),1],[(6,8),1],[(9,10),1]
  652. rq.add(4, 7, 0, 0); // double olap middle
  653. rq.dumplist(); // [(1,2),1], [(3,8),3], [(9,10),1]
  654. printf("C8:n");
  655. rq.init(1);
  656. rq.add(1, 2, 0, 0);
  657. rq.add(3, 5, 0, 0);
  658. rq.add(10, 12, 0, 0);
  659. rq.add(20, 30, 0, 0);
  660. rq.dumplist(); // [(1,2),1], [(3,5),1], [(10,12),1], [(20,30),1]
  661. rq.add(4, 8, 0, 0); // single olap middle
  662. rq.dumplist(); // [(1,2),1], [(3,8),2], [(10,12),1], [(20,30),1]
  663. rq.init(1);
  664. rq.add(1, 5, 0, 0);
  665. rq.add(10, 20, 0, 0);
  666. //rq.add(40321, 41281, 0, 0);
  667. //rq.add(42241, 43201, 0, 0);
  668. //rq.add(44161, 45121, 0, 0);
  669. rq.dumplist(); // [(1,5),1], [(10,20),1]
  670. //rq.add(40321, 41281, 0, 0);
  671. rq.add(1, 5, 0, 0);
  672. rq.dumplist(); // [(1,5),1], [(10,20),1]
  673. int x, y;
  674. printf("NH1: %dn", rq.nexthole(3, x, y));
  675. printf("NH2: %dn", rq.nexthole(5, x, y));
  676. printf("CLR to 4n");
  677. rq.clearto(4);
  678. rq.dumplist();
  679. exit(0);
  680. }
  681. #endif