001    // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 
002    // The Molly framework is freely distributable under the terms of an
003    // MIT-style license. For details, see the molly pages web site at:
004    // http://www.mollypages.org/. Use, modify, have fun !
005    
006    package fc.util;
007    
008    import java.util.*;
009    
010    
011    /** A set of char ranges. **/
012    public class CharRangeSet
013    {
014    CharRange seedRange;  
015    List union;
016    List intersect;
017    
018    /**
019    Constructs a new CharRangeSet with the initial set containing
020    only the specified charrange
021    
022    @param  cs  the initial charrange
023    **/
024    public CharRangeSet(CharRange cs) 
025      {
026      Argcheck.notnull(cs);
027      seedRange = cs; 
028      //do _not_ lazy instantiate, otherwise have to put in
029      //null checks in other places
030      union = new ArrayList();
031      intersect = new ArrayList();
032      }
033    
034    /**
035    Adds this specified range as a union to the existing set of 
036    ranges (for purposes of {@link inRange(char)} method). 
037    Overlapping ranges are ok.
038    
039    @param  cs  a charrange to unite with
040    @throws IllegalArgumentException 
041          if the specified range was null
042    **/
043    public void union(CharRange r) 
044      {
045      Argcheck.notnull(r);
046      union.add(r);
047      }
048    
049    /**
050    Adds the specified range as an intersection to the existing
051    ranges (for purposes of {@link inRange(char)} method). 
052    Overlapping ranges are ok. 
053    
054    @param  r the range to add
055    **/
056    public void intersection(CharRange r) 
057      {
058      Argcheck.notnull(r);  
059      intersect.add(r);
060      }
061    
062    /** 
063    Consider a set of ranges <tt>A</tt>, <tt>B</tt> added as a union
064    (logical <tt>or</tt>) and ranges <tt>C</tt> and <tt>D</tt> added as an
065    intersection (logical <tt>and</tt>). A character <tt>c</tt> is in range if
066    it exists in:
067    
068    <blockquote> <tt>
069    
070    (A.inRange(c) || B.inRange(c) || ...) && C.inRange(c) && D.inRange(c)
071    && ...
072    
073    </tt></blockquote> 
074    
075    This can be generalized to an arbitrary number of sub ranges. If
076    intersection or union ranges don't exist, then they are not
077    considered in the above expression. Note, the interaction may be
078    subtle if any of the ranges (<tt>A, B, C...</tt>etc) are
079    individually negated because in that case the inRange method for
080    that negated range would return true if the specified character
081    was <b>not</b> in that range.
082    
083    @return <tt>true</tt> if the passed in character is allowed by this 
084        set of ranges.
085    
086    **/
087    public boolean inRange(char c) 
088      {
089      boolean result = seedRange.inRange(c);
090      for (int i = 0, n = union.size(); i < n; i++) {
091        CharRange item = (CharRange) union.get(i);
092        result = result || item.inRange(c);
093        }   
094      for (int i = 0, n = intersect.size(); i < n; i++) {
095        CharRange item = (CharRange) intersect.get(i);
096        result = result && item.inRange(c);
097        } 
098      return result;
099      }
100    
101    public String toString() {
102      StringBuffer buf = new StringBuffer(128); 
103      buf.append("CharRangeSet:["); 
104      
105      if (intersect.size() > 0)
106        buf.append("(");
107    
108      buf.append(seedRange);
109    
110      int len = union.size();
111      if (len > 0) 
112          {
113          buf.append(" || " );
114          for (int i = 0; i < len; i++) {
115            buf.append(union.get(i).toString());
116            if (i < (len-1))
117              buf.append(" || ");
118            }     
119        }
120        
121      len = intersect.size();
122      if (len > 0) 
123        {
124          buf.append(") && " );     
125        for (int i = 0; i < len; i++) {
126          buf.append(intersect.get(i).toString());
127          if (i < (len-1))
128            buf.append(" && ");
129          }     
130        }
131        
132      buf.append("]");
133      return buf.toString();
134      }
135    
136    
137    public static void main(String[] args)
138      {
139      CharRange r = new CharRange('b', 'd');
140      CharRange r2 = new CharRange('x', 'y');
141      CharRangeSet crs = new CharRangeSet(r);
142      crs.union(r2);
143      System.out.println("constructed: " + crs);
144      
145      //normal
146      test(crs);
147      
148      crs.intersection(new CharRange('a', 'x'));
149      System.out.println("added intersection, now: ");
150      System.out.println(crs);
151      test(crs);
152    
153      crs.union(new CharRange('a', 'z'));
154      crs.intersection(new CharRange('s', 't'));
155      System.out.println("added union, intersection, now: ");
156      System.out.println(crs);
157      
158      test(crs);  
159      }
160    
161    private static void test(CharRangeSet r) 
162      {
163      System.out.println("'b' in range:" + r.inRange('b'));
164      System.out.println("'z' in range:" + r.inRange('z'));
165      System.out.println("'s' in range:" + r.inRange('s'));
166      System.out.println("'m' in range:" + r.inRange('m'));
167      } 
168    }