Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / gnu / java / text / FormatCharacterIterator.java
blob942641a0818a3508b92705a0088b11dd87b5bca9
1 /* FormatCharacter.java -- Implementation of AttributedCharacterIterator for
2 formatters.
3 Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA.
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
38 package gnu.java.text;
40 import gnu.classpath.Configuration;
42 import java.text.AttributedCharacterIterator;
43 import java.util.HashMap;
44 import java.util.HashSet;
45 import java.util.Iterator;
46 import java.util.Map;
47 import java.util.Set;
48 import java.util.Vector;
50 /**
51 * This class should not be put public and it is only intended to the
52 * classes of the java.text package. Its aim is to build a segmented
53 * character iterator by appending strings and adding attributes to
54 * portions of strings. The code intends to do some optimization
55 * concerning memory consumption and attribute access but at the
56 * end it is only an AttributedCharacterIterator.
58 * @author Guilhem Lavaux <guilhem@kaffe.org>
59 * @date November 22, 2003
61 public class FormatCharacterIterator implements AttributedCharacterIterator
63 private String formattedString;
64 private int charIndex;
65 private int attributeIndex;
66 private int[] ranges;
67 private HashMap[] attributes;
69 /**
70 * This constructor builds an empty iterated strings. The attributes
71 * are empty and so is the string. However you may append strings
72 * and attributes to this iterator.
74 public FormatCharacterIterator()
76 formattedString = "";
77 ranges = new int[0];
78 attributes = new HashMap[0];
81 /**
82 * This constructor take a string <code>s</code>, a set of ranges
83 * and the corresponding attributes. This is used to build an iterator.
84 * The array <code>ranges</code> should be formatted as follow:
85 * each element of <code>ranges</code> specifies the index in the string
86 * until which the corresponding map of attributes at the same position
87 * is applied. For example, if you have:
88 * <pre>
89 * s = "hello";
90 * ranges = new int[] { 2, 6 };
91 * attributes = new HashMap[2];
92 * </pre>
93 * <code>"he"</code> will have the attributes <code>attributes[0]</code>,
94 * <code>"llo"</code> the <code>attributes[1]</code>.
96 public FormatCharacterIterator (String s, int[] ranges, HashMap[] attributes)
98 formattedString = s;
99 this.ranges = ranges;
100 this.attributes = attributes;
104 * The following methods are inherited from AttributedCharacterIterator,
105 * and thus are already documented.
108 public Set getAllAttributeKeys()
110 if (attributes != null && attributes[attributeIndex] != null)
111 return attributes[attributeIndex].keySet();
112 else
113 return new HashSet();
116 public Map getAttributes()
118 if (attributes != null && attributes[attributeIndex] != null)
119 return attributes[attributeIndex];
120 else
121 return new HashMap();
124 public Object getAttribute (AttributedCharacterIterator.Attribute attrib)
126 if (attributes != null && attributes[attributeIndex] != null)
127 return attributes[attributeIndex].get (attrib);
128 else
129 return null;
132 public int getRunLimit(Set reqAttrs)
134 if (attributes == null)
135 return formattedString.length();
137 int currentAttrIndex = attributeIndex;
138 Set newKeys;
142 currentAttrIndex++;
143 if (currentAttrIndex == attributes.length)
144 return formattedString.length();
145 if (attributes[currentAttrIndex] == null)
146 break;
147 newKeys = attributes[currentAttrIndex].keySet();
149 while (newKeys.containsAll (reqAttrs));
151 return ranges[currentAttrIndex-1];
154 public int getRunLimit (AttributedCharacterIterator.Attribute attribute)
156 Set s = new HashSet();
158 s.add (attribute);
159 return getRunLimit (s);
162 public int getRunLimit()
164 if (attributes == null)
165 return formattedString.length();
166 if (attributes[attributeIndex] == null)
168 for (int i=attributeIndex+1;i<attributes.length;i++)
169 if (attributes[i] != null)
170 return ranges[i-1];
171 return formattedString.length();
174 return getRunLimit (attributes[attributeIndex].keySet());
177 public int getRunStart (Set reqAttrs)
179 if (attributes == null)
180 return formattedString.length();
182 int currentAttrIndex = attributeIndex;
183 Set newKeys = null;
187 if (currentAttrIndex == 0)
188 return 0;
190 currentAttrIndex--;
191 if (attributes[currentAttrIndex] == null)
192 break;
193 newKeys = attributes[currentAttrIndex].keySet();
195 while (newKeys.containsAll (reqAttrs));
197 return (currentAttrIndex > 0) ? ranges[currentAttrIndex-1] : 0;
200 public int getRunStart()
202 if (attributes == null)
203 return 0;
205 if (attributes[attributeIndex] == null)
207 for (int i=attributeIndex;i>0;i--)
208 if (attributes[i] != null)
209 return ranges[attributeIndex-1];
210 return 0;
213 return getRunStart (attributes[attributeIndex].keySet());
216 public int getRunStart (AttributedCharacterIterator.Attribute attribute)
218 Set s = new HashSet();
220 s.add (attribute);
221 return getRunStart (s);
224 public Object clone()
226 return new FormatCharacterIterator (formattedString, ranges, attributes);
230 * The following methods are inherited from CharacterIterator and thus
231 * are already documented.
234 public char current()
236 return formattedString.charAt (charIndex);
239 public char first()
241 charIndex = 0;
242 attributeIndex = 0;
243 return formattedString.charAt (0);
246 public int getBeginIndex()
248 return 0;
251 public int getEndIndex()
253 return formattedString.length();
256 public int getIndex()
258 return charIndex;
261 public char last()
263 charIndex = formattedString.length()-1;
264 if (attributes != null)
265 attributeIndex = attributes.length-1;
266 return formattedString.charAt (charIndex);
269 public char next()
271 charIndex++;
272 if (charIndex >= formattedString.length())
274 charIndex = getEndIndex();
275 return DONE;
277 if (attributes != null)
279 if (charIndex >= ranges[attributeIndex])
280 attributeIndex++;
282 return formattedString.charAt (charIndex);
285 public char previous()
287 charIndex--;
288 if (charIndex < 0)
290 charIndex = 0;
291 return DONE;
294 if (attributes != null)
296 if (charIndex < ranges[attributeIndex])
297 attributeIndex--;
299 return formattedString.charAt (charIndex);
302 public char setIndex (int position)
304 if (position < 0 || position > formattedString.length())
305 throw new IllegalArgumentException ("position is out of range");
307 charIndex = position;
308 if (attributes != null)
310 for (attributeIndex=0;attributeIndex<attributes.length;
311 attributeIndex++)
312 if (ranges[attributeIndex] > charIndex)
313 break;
314 attributeIndex--;
316 if (charIndex == formattedString.length())
317 return DONE;
318 else
319 return formattedString.charAt (charIndex);
323 * This method merge the specified attributes and ranges with the
324 * internal tables. This method is in charge of the optimization
325 * of tables. Two following sets of attributes are never the same.
327 * @see #FormatCharacterIterator()
329 * @param attributes the new array attributes to apply to the string.
331 public void mergeAttributes (HashMap[] attributes, int[] ranges)
333 Vector new_ranges = new Vector();
334 Vector new_attributes = new Vector();
335 int i = 0, j = 0;
337 debug("merging " + attributes.length + " attrs");
339 while (i < this.ranges.length && j < ranges.length)
341 if (this.attributes[i] != null)
343 new_attributes.add (this.attributes[i]);
344 if (attributes[j] != null)
345 this.attributes[i].putAll (attributes[j]);
347 else
349 new_attributes.add (attributes[j]);
351 if (this.ranges[i] == ranges[j])
353 new_ranges.add (new Integer (ranges[j]));
354 i++;
355 j++;
357 else if (this.ranges[i] < ranges[j])
359 new_ranges.add (new Integer (this.ranges[i]));
360 i++;
362 else
364 new_ranges.add (new Integer (ranges[j]));
365 j++;
369 if (i != this.ranges.length)
371 for (;i<this.ranges.length;i++)
373 new_attributes.add (this.attributes[i]);
374 new_ranges.add (new Integer (this.ranges[i]));
377 if (j != ranges.length)
379 for (;j<ranges.length;j++)
381 new_attributes.add (attributes[j]);
382 new_ranges.add (new Integer (ranges[j]));
386 this.attributes = new HashMap[new_attributes.size()];
387 this.ranges = new int[new_ranges.size()];
388 System.arraycopy (new_attributes.toArray(), 0, this.attributes,
389 0, this.attributes.length);
391 for (i=0;i<new_ranges.size();i++)
393 this.ranges[i] = ((Integer)new_ranges.elementAt (i)).intValue();
396 dumpTable();
400 * This method appends to the internal attributed string the attributed
401 * string contained in the specified iterator.
403 * @param iterator the iterator which contains the attributed string to
404 * append to this iterator.
406 public void append (AttributedCharacterIterator iterator)
408 char c = iterator.first();
409 Vector more_ranges = new Vector();
410 Vector more_attributes = new Vector();
414 formattedString = formattedString + String.valueOf (c);
415 // TODO: Reduce the size of the output array.
416 more_attributes.add (iterator.getAttributes());
417 more_ranges.add (new Integer (formattedString.length()));
418 // END TOOD
419 c = iterator.next();
421 while (c != DONE);
423 HashMap[] new_attributes = new HashMap[attributes.length
424 + more_attributes.size()];
425 int[] new_ranges = new int[ranges.length + more_ranges.size()];
427 System.arraycopy (attributes, 0, new_attributes, 0, attributes.length);
428 System.arraycopy (more_attributes.toArray(), 0, new_attributes,
429 attributes.length, more_attributes.size());
431 System.arraycopy (ranges, 0, new_ranges, 0, ranges.length);
432 Object[] new_ranges_array = more_ranges.toArray();
433 for (int i = 0; i < more_ranges.size();i++)
434 new_ranges[i+ranges.length] = ((Integer) new_ranges_array[i]).intValue();
436 attributes = new_attributes;
437 ranges = new_ranges;
441 * This method appends an attributed string which attributes are specified
442 * directly in the calling parameters.
444 * @param text The string to append.
445 * @param local_attributes The attributes to put on this string in the
446 * iterator. If it is <code>null</code> the string will simply have no
447 * attributes.
449 public void append (String text, HashMap local_attributes)
451 int[] new_ranges = new int[ranges.length+1];
452 HashMap[] new_attributes = new HashMap[attributes.length+1];
454 formattedString += text;
455 System.arraycopy (attributes, 0, new_attributes, 0, attributes.length);
456 System.arraycopy (ranges, 0, new_ranges, 0, ranges.length);
457 new_ranges[ranges.length] = formattedString.length();
458 new_attributes[attributes.length] = local_attributes;
460 ranges = new_ranges;
461 attributes = new_attributes;
465 * This method appends a string without attributes. It is completely
466 * equivalent to call {@link #append(String,HashMap)} with local_attributes
467 * equal to <code>null</code>.
469 * @param text The string to append to the iterator.
471 public void append (String text)
473 append (text, null);
477 * This method adds a set of attributes to a range of character. The
478 * bounds are always inclusive. In the case many attributes have to
479 * be added it is advised to directly use {@link #mergeAttributes([Ljava.util.HashMap;[I}
481 * @param attributes Attributes to merge into the iterator.
482 * @param range_start Lower bound of the range of characters which will receive the
483 * attribute.
484 * @param range_end Upper bound of the range of characters which will receive the
485 * attribute.
487 * @throws IllegalArgumentException if ranges are out of bounds.
489 public void addAttributes(HashMap attributes, int range_start, int range_end)
491 if (range_start == 0)
492 mergeAttributes(new HashMap[] { attributes }, new int[] { range_end });
493 else
494 mergeAttributes(new HashMap[] { null, attributes }, new int[] { range_start, range_end });
497 private void debug(String s)
499 if (Configuration.DEBUG)
500 System.out.println(s);
503 private void dumpTable()
505 int start_range = 0;
507 if (!Configuration.DEBUG)
508 return;
510 System.out.println("Dumping internal table:");
511 for (int i = 0; i < ranges.length; i++)
513 System.out.print("\t" + start_range + " => " + ranges[i] + ":");
514 if (attributes[i] == null)
515 System.out.println("null");
516 else
518 Set keyset = attributes[i].keySet();
519 if (keyset != null)
521 Iterator keys = keyset.iterator();
523 while (keys.hasNext())
524 System.out.print(" " + keys.next());
526 else
527 System.out.println("keySet null");
528 System.out.println();
531 System.out.println();
532 System.out.flush();