PageRenderTime 36ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre4/org/gjt/sp/jedit/buffer/PositionManager.java

#
Java | 704 lines | 530 code | 57 blank | 117 comment | 175 complexity | 77be3b54f91e39062f4ade6bd6c717e8 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * PositionManager.java - Manages positions
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2001, 2003 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit.buffer;
  23. //{{{ Imports
  24. import javax.swing.text.*;
  25. import org.gjt.sp.jedit.syntax.*;
  26. import org.gjt.sp.jedit.Buffer;
  27. import org.gjt.sp.jedit.Debug;
  28. import org.gjt.sp.jedit.MiscUtilities;
  29. import org.gjt.sp.util.IntegerArray;
  30. import org.gjt.sp.util.Log;
  31. //}}}
  32. /**
  33. * A class internal to jEdit's document model. You should not use it
  34. * directly. To improve performance, none of the methods in this class
  35. * check for out of bounds access, nor are they thread-safe. The
  36. * <code>Buffer</code> class, through which these methods must be
  37. * called through, implements such protection.
  38. *
  39. * @author Slava Pestov
  40. * @version $Id: PositionManager.java 4843 2003-08-04 03:19:13Z spestov $
  41. * @since jEdit 4.2pre3
  42. */
  43. public class PositionManager
  44. {
  45. //{{{ createPosition() method
  46. public synchronized Position createPosition(int offset)
  47. {
  48. //System.err.println(this + ": create " + offset);
  49. PosBottomHalf bh;
  50. // moves gap to offset if necessary
  51. contentInserted(offset,0);
  52. if(root == null)
  53. root = bh = new PosBottomHalf(offset - gapWidth);
  54. else
  55. {
  56. bh = root.find(offset);
  57. if(bh == null)
  58. {
  59. bh = new PosBottomHalf(offset - gapWidth);
  60. bh.red = true;
  61. root.insert(bh);
  62. if(!Debug.DISABLE_POSITION_BALANCE)
  63. ibalance(bh);
  64. }
  65. }
  66. /* if(root != null)
  67. check(root,new java.util.Vector()); */
  68. /* if(Debug.POSITION_DEBUG)
  69. root.dump(0); */
  70. return new PosTopHalf(bh);
  71. } //}}}
  72. //{{{ contentInserted() method
  73. public synchronized void contentInserted(int offset, int length)
  74. {
  75. if(root == null)
  76. {
  77. gapWidth = 0;
  78. return;
  79. }
  80. if(gapWidth != 0)
  81. {
  82. if(gapOffset < offset)
  83. root.contentInserted(gapOffset,offset,gapWidth);
  84. else
  85. root.contentInserted(offset,gapOffset,-gapWidth);
  86. }
  87. gapOffset = offset;
  88. gapWidth += length;
  89. } //}}}
  90. //{{{ contentRemoved() method
  91. public synchronized void contentRemoved(int offset, int length)
  92. {
  93. if(root == null)
  94. {
  95. gapWidth = 0;
  96. return;
  97. }
  98. if(gapWidth != 0 && gapOffset < offset)
  99. {
  100. root.contentRemoved(gapOffset,offset,offset + length,
  101. gapWidth,true);
  102. }
  103. else if(gapWidth != 0 && gapOffset > offset + length)
  104. {
  105. root.contentRemoved(offset,offset + length,gapOffset,
  106. gapWidth,false);
  107. }
  108. else
  109. {
  110. root.contentRemoved(offset,offset + length,
  111. offset + length,gapWidth,false);
  112. }
  113. gapOffset = offset;
  114. gapWidth -= length;
  115. } //}}}
  116. //{{{ Package-private members
  117. /* so that PosBottomHalf can access without access$ methods */
  118. int gapOffset;
  119. int gapWidth;
  120. //{{{ removePosition() method
  121. private void removePosition(PosBottomHalf bh)
  122. {
  123. if(Debug.POSITION_DEBUG)
  124. Log.log(Log.DEBUG,this,"killing " + bh);
  125. PosBottomHalf r, x = bh.parent;
  126. // if one of the siblings is null, make &this=non null sibling
  127. if(bh.left == null)
  128. {
  129. r = bh.right;
  130. if(bh.parent == null)
  131. {
  132. if(Debug.POSITION_DEBUG)
  133. Log.log(Log.DEBUG,this,"simple/left: setting root to " + bh.right);
  134. root = bh.right;
  135. }
  136. else
  137. {
  138. if(bh == bh.parent.left)
  139. bh.parent.left = bh.right;
  140. else
  141. bh.parent.right = bh.right;
  142. }
  143. if(bh.right != null)
  144. {
  145. if(Debug.POSITION_DEBUG)
  146. Log.log(Log.DEBUG,this,"134: " + bh.right+":"+bh.parent);
  147. bh.right.parent = bh.parent;
  148. }
  149. }
  150. else if(bh.right == null)
  151. {
  152. r = bh.left;
  153. if(bh.parent == null)
  154. {
  155. if(Debug.POSITION_DEBUG)
  156. Log.log(Log.DEBUG,this,"simple/right: setting root " + bh.left);
  157. root = bh.left;
  158. }
  159. else
  160. {
  161. if(bh == bh.parent.left)
  162. bh.parent.left = bh.left;
  163. else
  164. bh.parent.right = bh.left;
  165. }
  166. if(bh.left != null)
  167. {
  168. if(Debug.POSITION_DEBUG)
  169. Log.log(Log.DEBUG,this,"155: "+bh.left+":" + bh.parent);
  170. bh.left.parent = bh.parent;
  171. }
  172. }
  173. // neither is null
  174. else
  175. {
  176. PosBottomHalf nextInorder = bh.right;
  177. r = nextInorder;
  178. while(nextInorder.left != null)
  179. {
  180. nextInorder = nextInorder.left;
  181. r = nextInorder.right;
  182. }
  183. // removing the root?
  184. if(bh.parent == null)
  185. {
  186. if(Debug.POSITION_DEBUG)
  187. Log.log(Log.DEBUG,this,"nextInorder: setting root to " + nextInorder);
  188. root = nextInorder;
  189. }
  190. else
  191. {
  192. if(bh.parent.left == bh)
  193. bh.parent.left = nextInorder;
  194. else
  195. bh.parent.right = nextInorder;
  196. }
  197. if(nextInorder != bh.right)
  198. {
  199. nextInorder.parent.left = nextInorder.right;
  200. if(nextInorder.right != null)
  201. {
  202. if(Debug.POSITION_DEBUG)
  203. Log.log(Log.DEBUG,this,"182: "+nextInorder.right+":" + nextInorder.parent);
  204. nextInorder.right.parent = nextInorder.parent;
  205. }
  206. nextInorder.right = bh.right;
  207. if(Debug.POSITION_DEBUG)
  208. Log.log(Log.DEBUG,this,"186: "+nextInorder.right+":" + nextInorder);
  209. nextInorder.right.parent = nextInorder;
  210. }
  211. x = nextInorder.parent;
  212. if(Debug.POSITION_DEBUG)
  213. Log.log(Log.DEBUG,this,"189: "+nextInorder+":" + bh.parent);
  214. nextInorder.parent = bh.parent;
  215. nextInorder.left = bh.left;
  216. if(Debug.POSITION_DEBUG)
  217. Log.log(Log.DEBUG,this,"192: "+nextInorder.left+":" + nextInorder);
  218. nextInorder.left.parent = nextInorder;
  219. }
  220. if(!bh.red)
  221. {
  222. if(r != null && r.red)
  223. r.red = false;
  224. else if(x != null && r != null)
  225. {
  226. if(!Debug.DISABLE_POSITION_BALANCE)
  227. rbalance(r,x);
  228. }
  229. }
  230. if(Debug.POSITION_DEBUG && root != null)
  231. root.dump(0);
  232. } //}}}
  233. //}}}
  234. //{{{ Private members
  235. private PosBottomHalf root;
  236. //{{{ ibalance() method
  237. private void ibalance(PosBottomHalf bh)
  238. {
  239. if(bh.parent.red)
  240. {
  241. PosBottomHalf u = bh.parent.parent;
  242. PosBottomHalf w = bh.parent.sibling();
  243. if(w != null && w.red)
  244. {
  245. if(Debug.POSITION_DEBUG)
  246. Log.log(Log.DEBUG,this,"case 2");
  247. bh.parent.red = false;
  248. w.red = false;
  249. if(u.parent == null)
  250. u.red = false;
  251. else
  252. {
  253. u.red = true;
  254. ibalance(u);
  255. }
  256. }
  257. else
  258. {
  259. if(Debug.POSITION_DEBUG)
  260. Log.log(Log.DEBUG,this,"case 1");
  261. PosBottomHalf b = bh.restructure();
  262. b.red = false;
  263. b.left.red = true;
  264. b.right.red = true;
  265. }
  266. }
  267. } //}}}
  268. //{{{ rbalance() method
  269. private void rbalance(PosBottomHalf r, PosBottomHalf x)
  270. {
  271. PosBottomHalf y = r.sibling();
  272. PosBottomHalf z;
  273. if(y.red)
  274. {
  275. if(Debug.POSITION_DEBUG)
  276. Log.log(Log.DEBUG,this,"case 3");
  277. if(x.right == y)
  278. z = y.right;
  279. else if(x.left == y)
  280. z = y.left;
  281. else
  282. throw new InternalError();
  283. PosBottomHalf b = z.restructure();
  284. y.red = false;
  285. x.red = true;
  286. // different meaning of x and y
  287. rbalance(r,r.sibling());
  288. }
  289. else
  290. {
  291. r.red = false;
  292. if(y.left != null && y.left.red)
  293. z = y.left;
  294. else if(y.right != null && y.right.red)
  295. z = y.right;
  296. else
  297. {
  298. if(Debug.POSITION_DEBUG)
  299. Log.log(Log.DEBUG,this,"case 2");
  300. y.red = true;
  301. if(x.red)
  302. x.red = false;
  303. else if(x.parent != null)
  304. rbalance(x,x.parent);
  305. return;
  306. }
  307. if(Debug.POSITION_DEBUG)
  308. Log.log(Log.DEBUG,this,"case 1");
  309. boolean oldXRed = x.red;
  310. PosBottomHalf b = z.restructure();
  311. b.left.red = false;
  312. b.right.red = false;
  313. b.red = oldXRed;
  314. }
  315. } //}}}
  316. //}}}
  317. //{{{ Inner classes
  318. //{{{ PosTopHalf class
  319. class PosTopHalf implements Position
  320. {
  321. PosBottomHalf bh;
  322. //{{{ PosTopHalf constructor
  323. PosTopHalf(PosBottomHalf bh)
  324. {
  325. this.bh = bh;
  326. bh.ref();
  327. } //}}}
  328. //{{{ getOffset() method
  329. public int getOffset()
  330. {
  331. return bh.getOffset();
  332. } //}}}
  333. //{{{ finalize() method
  334. public void finalize()
  335. {
  336. synchronized(PositionManager.this)
  337. {
  338. bh.unref();
  339. }
  340. } //}}}
  341. } //}}}
  342. //{{{ PosBottomHalf class
  343. class PosBottomHalf
  344. {
  345. int offset;
  346. int ref;
  347. PosBottomHalf parent;
  348. PosBottomHalf left, right;
  349. boolean red;
  350. //{{{ PosBottomHalf constructor
  351. PosBottomHalf(int offset)
  352. {
  353. this.offset = offset;
  354. } //}}}
  355. //{{{ getOffset() method
  356. int getOffset()
  357. {
  358. if(offset >= gapOffset)
  359. return offset + gapWidth;
  360. else
  361. return offset;
  362. } //}}}
  363. //{{{ dump() method
  364. void dump(int level)
  365. {
  366. String ws = MiscUtilities.createWhiteSpace(level,0);
  367. if(left != null)
  368. left.dump(level+1);
  369. else
  370. {
  371. Log.log(Log.DEBUG,this,ws + " /]");
  372. }
  373. Log.log(Log.DEBUG,this,ws + red + ":" + getOffset());
  374. if(right != null)
  375. right.dump(level+1);
  376. else
  377. {
  378. Log.log(Log.DEBUG,this,ws + " \\]");
  379. }
  380. } //}}}
  381. //{{{ insert() method
  382. void insert(PosBottomHalf pos)
  383. {
  384. if(pos.getOffset() < getOffset())
  385. {
  386. if(left == null)
  387. {
  388. if(Debug.POSITION_DEBUG)
  389. Log.log(Log.DEBUG,this,"382: "+pos+":" + this);
  390. pos.parent = this;
  391. left = pos;
  392. }
  393. else
  394. left.insert(pos);
  395. }
  396. else
  397. {
  398. if(right == null)
  399. {
  400. if(Debug.POSITION_DEBUG)
  401. Log.log(Log.DEBUG,this,"393: "+pos+":" + this);
  402. pos.parent = this;
  403. right = pos;
  404. }
  405. else
  406. right.insert(pos);
  407. }
  408. } //}}}
  409. //{{{ find() method
  410. PosBottomHalf find(int offset)
  411. {
  412. if(getOffset() == offset)
  413. return this;
  414. else if(getOffset() < offset)
  415. {
  416. if(right == null)
  417. return null;
  418. else
  419. return right.find(offset);
  420. }
  421. else
  422. {
  423. if(left == null)
  424. return null;
  425. else
  426. return left.find(offset);
  427. }
  428. } //}}}
  429. //{{{ sibling() method
  430. PosBottomHalf sibling()
  431. {
  432. if(parent.left == this)
  433. return parent.right;
  434. else if(parent.right == this)
  435. return parent.left;
  436. else
  437. throw new InternalError();
  438. } //}}}
  439. //{{{ contentInserted() method
  440. /* update all nodes between start and end by length */
  441. void contentInserted(int start, int end, int length)
  442. {
  443. if(getOffset() < start)
  444. {
  445. if(right != null)
  446. right.contentInserted(start,end,length);
  447. }
  448. else if(getOffset() > end)
  449. {
  450. if(left != null)
  451. left.contentInserted(start,end,length);
  452. }
  453. else
  454. {
  455. offset += length;
  456. if(left != null)
  457. left.contentInserted(start,end,length);
  458. if(right != null)
  459. right.contentInserted(start,end,length);
  460. }
  461. } //}}}
  462. //{{{ contentRemoved() method
  463. /* if bias: kill from p1 to p2, update from p2 to p3,
  464. * if !bias: update from p1 to p2, kill from p2 to p3 */
  465. void contentRemoved(int p1, int p2, int p3, int length,
  466. boolean bias)
  467. {
  468. if(getOffset() < p1)
  469. {
  470. if(right != null)
  471. right.contentRemoved(p1,p2,p3,length,bias);
  472. }
  473. else if(getOffset() > p3)
  474. {
  475. if(left != null)
  476. left.contentRemoved(p1,p2,p3,length,bias);
  477. }
  478. else
  479. {
  480. if(bias)
  481. {
  482. if(getOffset() >= p2)
  483. offset = p2 - length;
  484. else
  485. offset += length;
  486. }
  487. else
  488. {
  489. if(getOffset() <= p2)
  490. offset = p2 - length;
  491. else
  492. offset -= length;
  493. }
  494. if(left != null)
  495. left.contentRemoved(p1,p2,p3,length,bias);
  496. if(right != null)
  497. right.contentRemoved(p1,p2,p3,length,bias);
  498. }
  499. } //}}}
  500. //{{{ ref() method
  501. void ref()
  502. {
  503. ref++;
  504. } //}}}
  505. //{{{ unref() method
  506. void unref()
  507. {
  508. if(--ref == 0)
  509. removePosition(this);
  510. } //}}}
  511. //{{{ restructure() method
  512. private PosBottomHalf restructure()
  513. {
  514. // this method looks incomprehensible but really
  515. // its quite simple. this node, its parent and its
  516. // grandparent are rearranged such that in-ordering
  517. // of the tree is preserved, and so that the tree
  518. // looks like so:
  519. //
  520. // (b)
  521. // / \
  522. // (a) (c)
  523. //
  524. // Where a/b/c are the first, second and third in an
  525. // in-order traversal of this node, the parent and the
  526. // grandparent.
  527. // Temporary storage: { al, a, ar, b, cl, c, cr }
  528. PosBottomHalf[] nodes;
  529. // For clarity
  530. PosBottomHalf u = parent.parent;
  531. if(u.left == parent)
  532. {
  533. if(parent.left == this)
  534. {
  535. // u
  536. // /
  537. // v
  538. // /
  539. // z
  540. if(Debug.POSITION_DEBUG)
  541. Log.log(Log.DEBUG,this,"restructure 1");
  542. // zl, z, zr, v, vr, u, ur
  543. nodes = new PosBottomHalf[] {
  544. left, this, right,
  545. parent, parent.right,
  546. u, u.right
  547. };
  548. }
  549. else
  550. {
  551. // u
  552. // /
  553. // v
  554. // \
  555. // z
  556. if(Debug.POSITION_DEBUG)
  557. Log.log(Log.DEBUG,this,"restructure 2");
  558. // vl, v, zl, z, zr, u, ur
  559. nodes = new PosBottomHalf[] {
  560. parent.left, parent, left,
  561. this, right, u, u.right
  562. };
  563. }
  564. }
  565. else
  566. {
  567. if(parent.right == this)
  568. {
  569. // u
  570. // \
  571. // v
  572. // \
  573. // z
  574. if(Debug.POSITION_DEBUG)
  575. Log.log(Log.DEBUG,this,"restructure 3");
  576. // ul, u, vl, v, zl, z, zr
  577. nodes = new PosBottomHalf[] {
  578. u.left, u, parent.left,
  579. parent, left, this, right
  580. };
  581. }
  582. else
  583. {
  584. // u
  585. // \
  586. // v
  587. // /
  588. // z
  589. if(Debug.POSITION_DEBUG)
  590. Log.log(Log.DEBUG,this,"restructure 4");
  591. // ul, u, zl, z, zr, v, vr
  592. nodes = new PosBottomHalf[] {
  593. u.left, u, left, this, right,
  594. parent, parent.right
  595. };
  596. }
  597. }
  598. PosBottomHalf t = u.parent;
  599. if(t != null)
  600. {
  601. if(t.left == u)
  602. t.left = nodes[3];
  603. else
  604. t.right = nodes[3];
  605. }
  606. else
  607. {
  608. if(Debug.POSITION_DEBUG)
  609. Log.log(Log.DEBUG,this,"restructure: setting root to " + nodes[3]);
  610. root = nodes[3];
  611. }
  612. // Write-only code for constructing a meaningful tree
  613. if(Debug.POSITION_DEBUG)
  614. Log.log(Log.DEBUG,this,"583: "+nodes[1]+":" + nodes[3]);
  615. if(nodes[0] != null)
  616. nodes[0].parent = nodes[1];
  617. nodes[1].parent = nodes[3];
  618. nodes[1].left = nodes[0];
  619. nodes[1].right = nodes[2];
  620. if(nodes[2] != null)
  621. nodes[2].parent = nodes[1];
  622. if(Debug.POSITION_DEBUG)
  623. Log.log(Log.DEBUG,this,"setting parent to " + t);
  624. if(Debug.POSITION_DEBUG)
  625. Log.log(Log.DEBUG,this,"590: " + nodes[3]+":" + t);
  626. nodes[3].parent = t;
  627. nodes[3].left = nodes[1];
  628. nodes[3].right = nodes[5];
  629. if(Debug.POSITION_DEBUG)
  630. Log.log(Log.DEBUG,this,"595: "+nodes[5]+":" + nodes[3]);
  631. if(nodes[4] != null)
  632. nodes[4].parent = nodes[5];
  633. nodes[5].parent = nodes[3];
  634. nodes[5].left = nodes[4];
  635. nodes[5].right = nodes[6];
  636. if(nodes[6] != null)
  637. nodes[6].parent = nodes[5];
  638. return nodes[3];
  639. } //}}}
  640. //{{{ toString() method
  641. public String toString()
  642. {
  643. return red + ":" + getOffset();
  644. } //}}}
  645. } //}}}
  646. //}}}
  647. }