001: /*
002: * Sun Public License Notice
003: *
004: * The contents of this file are subject to the Sun Public License
005: * Version 1.0 (the "License"). You may not use this file except in
006: * compliance with the License. A copy of the License is available at
007: * http://www.sun.com/
008: *
009: * The Original Code is NetBeans. The Initial Developer of the Original
010: * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
011: * Microsystems, Inc. All Rights Reserved.
012: */
013:
014: package org.netbeans.editor;
015:
016: import java.lang.ref.WeakReference;
017: import java.util.ArrayList;
018:
019: import javax.swing.text.BadLocationException;
020: import javax.swing.text.Segment;
021:
022: /**
023: * Encapsulation of a special static segment used by syntax scanners.
024: * Unfortunately document cache cannot guarantee that its fragment(s) will hold
025: * more than one character at the time so syntax scanning cannot be done by
026: * finder. Instead all the syntax analyzes are done over the syntax segment's
027: * data. Although it's shared across all instances of editors the loads into it
028: * should be fast as they are done from cache fragments by arraycopy() method.
029: * The syntax segment is separated into the slots because there can be more
030: * scanning necessary at one time. All the scanning must be done
031: *
032: * @author Miloslav Metelka
033: * @version 1.00
034: */
035: class SyntaxSeg extends Segment {
036:
037: private static final char[] EMPTY_CHAR_ARRAY = new char[0];
038:
039: private static final int MAX_SLOT_COUNT = 100;
040:
041: private static final int REALLOC_INCREMENT = 2048;
042:
043: private static ArrayList slotList = new ArrayList();
044:
045: static synchronized Slot getFreeSlot() {
046: int cnt = slotList.size();
047: return (cnt > 0) ? (Slot) slotList.remove(cnt - 1) : new Slot();
048: }
049:
050: static synchronized void releaseSlot(Slot slot) {
051: slotList.add(slot);
052: }
053:
054: /**
055: * From this position on, the data in syntax segment must be marked invalid.
056: */
057: static synchronized void invalidate(BaseDocument doc, int pos) {
058: int cnt = slotList.size();
059: for (int i = 0; i < cnt; i++) {
060: ((Slot) slotList.get(i)).invalidate(doc, pos);
061: }
062: }
063:
064: static class Slot extends Segment {
065:
066: /** Document from which the data in syntax segment come from */
067: WeakReference segDocRef = new WeakReference(null);
068:
069: /** Begining of valid data in syntax segment */
070: int segPos;
071:
072: /** Begining of valid data in syntax segment */
073: int segLen;
074:
075: Slot() {
076: this .array = EMPTY_CHAR_ARRAY;
077: }
078:
079: /**
080: * Load the syntax segment if necessary from some location in some
081: * document. For best performance there's no pos or len correctness
082: * checking. Therefore caller must guarantee the correctness.
083: *
084: * @return real length that was loaded (syntax segment has limitation in
085: * size)
086: */
087: int load(BaseDocument doc, int pos, int len)
088: throws BadLocationException {
089: if (len <= 0) {
090: if (len == 0) {
091: count = 0;
092: return 0;
093: }
094: throw new RuntimeException("len=" + len); // Critical error
095: // NOI18N
096: }
097:
098: BaseDocument segDoc = (BaseDocument) segDocRef.get();
099: boolean difDoc = (doc != segDoc);
100: if (difDoc) {
101: segDoc = doc;
102: segDocRef = new WeakReference(segDoc);
103: }
104:
105: if (difDoc // different documents
106: || pos < segPos // position too low
107: || pos > segPos + segLen // position too high
108: || pos - segPos + len > array.length) { // wouldn't fit
109:
110: // possibly realloc the array
111: if (len > array.length) {
112: char tmp[] = new char[len + REALLOC_INCREMENT];
113: array = tmp; // original data are not recopied
114: }
115:
116: segPos = pos;
117: segLen = len;
118:
119: doc.getChars(pos, array, 0, len); // read chars into array
120:
121: } else { // inside array and will fit
122:
123: int endSegPos = segPos + segLen;
124: int restLen = pos + len - endSegPos;
125: if (restLen > 0) { // not fully inside
126: doc.getChars(endSegPos, array, segLen, restLen);
127: segLen += restLen;
128: }
129:
130: }
131:
132: offset = pos - segPos;
133: count = len;
134: if (offset < 0 || len < 0) {
135: throw new BadLocationException("pos=" + pos
136: + ", offset=" + offset // NOI18N
137: + "len=" + len, offset); // Critical error NOI18N
138: }
139: return len;
140: }
141:
142: /** Is the area inside the segment? */
143: boolean isAreaInside(BaseDocument doc, int pos, int len) {
144: return (doc == (BaseDocument) segDocRef.get()
145: && pos >= segPos && pos + len <= segPos + segLen);
146: }
147:
148: /**
149: * Invalidate the slot if it contains the data from the given document.
150: *
151: * @param doc
152: * document in which the change occured
153: * @param pos
154: * position in the document where the change occured
155: */
156: void invalidate(BaseDocument doc, int pos) {
157: if (doc == (BaseDocument) segDocRef.get()) {
158: if (pos < segPos) {
159: segLen = 0;
160: } else if (pos < segPos + segLen) {
161: segLen = pos - segPos;
162: }
163: }
164: }
165:
166: }
167:
168: }
|