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
006package fc.util;
007
008import java.util.*;
009
010
011/** A set of char ranges. **/
012public class CharRangeSet
013{
014CharRange seedRange;  
015List union;
016List intersect;
017
018/**
019Constructs a new CharRangeSet with the initial set containing
020only the specified charrange
021
022@param  cs  the initial charrange
023**/
024public 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/**
035Adds this specified range as a union to the existing set of 
036ranges (for purposes of {@link inRange(char)} method). 
037Overlapping ranges are ok.
038
039@param  cs  a charrange to unite with
040@throws IllegalArgumentException 
041      if the specified range was null
042**/
043public void union(CharRange r) 
044  {
045  Argcheck.notnull(r);
046  union.add(r);
047  }
048
049/**
050Adds the specified range as an intersection to the existing
051ranges (for purposes of {@link inRange(char)} method). 
052Overlapping ranges are ok. 
053
054@param  r the range to add
055**/
056public void intersection(CharRange r) 
057  {
058  Argcheck.notnull(r);  
059  intersect.add(r);
060  }
061
062/** 
063Consider 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
065intersection (logical <tt>and</tt>). A character <tt>c</tt> is in range if
066it 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
075This can be generalized to an arbitrary number of sub ranges. If
076intersection or union ranges don't exist, then they are not
077considered in the above expression. Note, the interaction may be
078subtle if any of the ranges (<tt>A, B, C...</tt>etc) are
079individually negated because in that case the inRange method for
080that negated range would return true if the specified character
081was <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**/
087public 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
101public 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
137public 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
161private 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}