diff --git a/icu4j/src/com/ibm/richtext/textlayout/attributes/AttributeMap.java b/icu4j/src/com/ibm/richtext/textlayout/attributes/AttributeMap.java new file mode 100755 index 00000000000..c8239288ede --- /dev/null +++ b/icu4j/src/com/ibm/richtext/textlayout/attributes/AttributeMap.java @@ -0,0 +1,529 @@ +/* + * @(#)$RCSfile: AttributeMap.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:33:31 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +// Requires Java2 +package com.ibm.textlayout.attributes; + +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Set; + +import java.io.Externalizable; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.IOException; + + +/** + * AttributeMap is an immutable Map. Additionally, there are + * several methods for common operations (union, + * remove, intersect); these methods return new AttributeMap + * instances. + *

+ * Although any non-null Object can be a key or value in an + * AttributeMap, typically the keys are fields of TextAttribute. + * @see TextAttribute + */ +public final class AttributeMap implements java.util.Map, + com.ibm.textlayout.attributes.Map, + Externalizable { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + private static final int CURRENT_VERSION = 1; + + private static final long serialVersionUID = 9510803; + + private static final String errString = "StyleSets are immutable."; + + // This is passed to the Hashtable constructor as the + // load factor argument. It is chosen to avoid resizing + // the Hashtable whenever possible. I think that 1 + // does this. + private static final int LOAD_FACTOR = 1; + + private Hashtable styleTable; + private transient AttributeSet cachedKeySet = null; + private transient Collection cachedValueCollection = null; + private transient Set cachedEntrySet = null; + + /** + * An empty AttributeMap. + */ + public static final AttributeMap EMPTY_ATTRIBUTE_MAP = new AttributeMap(); + +// ============== +// Constructors +// ============== + + /** + * Create a new, empty AttributeMap. EMPTY_STYLE_SET can be used + * in place of an AttributeMap produced by this constructor. + */ + public AttributeMap() { + + styleTable = new Hashtable(1, LOAD_FACTOR); + } + + /** + * Create an AttributeMap with the same key-value + * entries as the given Map. + * @param map a Map whose key-value entries will + * become the entries for this AttributeMap. map + * is not modified, and must not contain null keys or values. + */ + public AttributeMap(java.util.Map map) { + + styleTable = new Hashtable(map.size(), LOAD_FACTOR); + styleTable.putAll(map); + } + + /** + * Create an AttributeMap with the same key-value + * entries as the given Hashtable. + * @param table a Hashtable whose key-value entries will + * become the entries for this AttributeMap. table + * is not modified. + */ + public AttributeMap(Hashtable hashtable) { + + this((java.util.Map) hashtable); + } + + /** + * Create an AttributeMap with a single entry of + * {attribute, value}. + * @param attribute the key in this AttributeMap's single entry + * @param value the value in this AttributeMap's single entry + */ + public AttributeMap(Object key, Object value) { + + styleTable = new Hashtable(1, LOAD_FACTOR); + + // hashtable checks value for null + styleTable.put(key, value); + } + + // For internal use only. + private AttributeMap(Hashtable table, boolean clone) { + + if (clone) { + styleTable = (Hashtable) table.clone(); + } + else { + this.styleTable = table; + } + } + + public void writeExternal(ObjectOutput out) throws IOException { + + out.writeInt(CURRENT_VERSION); + out.writeInt(styleTable.size()); + Enumeration e = styleTable.keys(); + while (e.hasMoreElements()) { + Object key = e.nextElement(); + out.writeObject(AttributeKey.mapAttributeToKey(key)); + out.writeObject(styleTable.get(key)); + } + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + + if (in.readInt() != CURRENT_VERSION) { + throw new IOException("Invalid version of StyleBuffer"); + } + + int count = in.readInt(); + for (int i=0; i < count; i += 1) { + Object key = AttributeKey.mapKeyToAttribute(in.readObject()); + Object value = in.readObject(); + styleTable.put(key, value); + } + } + +// ============== +// Map interface +// ============== + +// queries + /** + * Return the number of entries in the AttributeMap. + * @return the number of entries in the AttributeMap + */ + public int size() { + + return styleTable.size(); + } + + /** + * Return true if the number of entries in the AttributeMap + * is 0. + * @return true if the number of entries in the AttributeMap + * is 0 + */ + public boolean isEmpty() { + + return styleTable.isEmpty(); + } + + /** + * Return true if the given key is in this AttributeMap. + * @param key the key to test + * @return true if key is in this AttributeMap + */ + public boolean containsKey(Object key) { + + return styleTable.containsKey(key); + } + + /** + * Return true if the given value is in this AttributeMap. + * @param key the value to test + * @return true if value is in this AttributeMap + */ + public boolean containsValue(Object value) { + + return styleTable.containsValue(value); + } + + /** + * Return the value associated with the given key. If the + * key is not in this AttributeMap null is returned. + * @param key the key to look up + * @return the value associated with key, or + * null if key is not in this AttributeMap + */ + public Object get(Object key) { + + return styleTable.get(key); + } + +// modifiers - all throw exceptions + + /** + * Throws UnsupportedOperationException. + * @see #addAttribute + * @throws UnsupportedOperationException + */ + public Object put(Object key, Object value) { + + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #removeAttributes + * @throws UnsupportedOperationException + */ + public Object remove(Object key) { + + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #addAttributes + * @throws UnsupportedOperationException + */ + public void putAll(java.util.Map t) { + + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #EMPTY_ATTRIBUTE_MAP + * @throws UnsupportedOperationException + */ + public void clear() { + + throw new UnsupportedOperationException(errString); + } + +// views + + /** + * Return an AttributeSet containing every key in this AttributeMap. + * @return an AttributeSet containing every key in this AttributeMap + */ + public Set keySet() { + + return getKeySet(); + } + + /** + * Return an AttributeSet containing every key in this AttributeMap. + * @return an AttributeSet containing every key in this AttributeMap + */ + public AttributeSet getKeySet() { + + AttributeSet result = cachedKeySet; + + if (result == null) { + result = AttributeSet.createKeySet(styleTable); + cachedKeySet = result; + } + + return result; + } + + /** + * Return a Collection containing every value in this AttributeMap. + * @return a Collection containing every value in this AttributeMap + */ + public Collection values() { + + Collection result = cachedValueCollection; + + if (result == null) { + result = Collections.unmodifiableCollection(styleTable.values()); + cachedValueCollection = result; + } + + return result; + } + + /** + * Return a Set containing all entries in this AttributeMap. + */ + public Set entrySet() { + + Set result = cachedEntrySet; + + if (result == null) { + result = Collections.unmodifiableSet(styleTable.entrySet()); + cachedEntrySet = result; + } + + return result; + } + + public boolean equals(Object rhs) { + + if (rhs == this) { + return true; + } + + if (rhs == null) { + return false; + } + + AttributeMap rhsStyleSet = null; + + try { + rhsStyleSet = (AttributeMap) rhs; + } + catch(ClassCastException e) { + return false; + } + + return styleTable.equals(rhsStyleSet.styleTable); + } + + public int hashCode() { + + return styleTable.hashCode(); + } + + public String toString() { + + return styleTable.toString(); + } + +// ============== +// Operations +// ============== + + /** + * Return a AttributeMap which contains entries in this AttributeMap, + * along with an entry for . If attribute + * is already present in this AttributeMap its value becomes value. + */ + public AttributeMap addAttribute(Object key, Object value) { + + // try to optimize for case where is already there? + Hashtable newTable = new Hashtable(styleTable.size() + 1, LOAD_FACTOR); + newTable.putAll(styleTable); + newTable.put(key, value); + return new AttributeMap(newTable, false); + } + + /** + * Return a AttributeMap which contains entries in this AttributeMap + * and in rhs. If an attribute appears in both StyleSets the + * value from rhs is used. + */ + public AttributeMap addAttributes(AttributeMap rhs) { + + int thisSize = size(); + + if (thisSize == 0) { + return rhs; + } + + int otherSize = rhs.size(); + + if (otherSize == 0) { + return this; + } + + Hashtable newTable = new Hashtable(thisSize + otherSize, LOAD_FACTOR); + + newTable.putAll(styleTable); + newTable.putAll(rhs); + + return new AttributeMap(newTable, false); + } + + /** + * Return a AttributeMap which contains entries in this AttributeMap + * and in rhs. If an attribute appears in both StyleSets the + * value from rhs is used. + * The Map's keys and values must be non-null. + */ + public AttributeMap addAttributes(java.util.Map rhs) { + + if (rhs instanceof AttributeMap) { + return addAttributes((AttributeMap)rhs); + } + + Hashtable newTable = new Hashtable(size() + rhs.size(), LOAD_FACTOR); + + newTable.putAll(styleTable); + newTable.putAll(rhs); + + return new AttributeMap(newTable, false); + } + + /** + * Return a AttributeMap with the entries in this AttributeMap, but + * without attribute as a key. + */ + public AttributeMap removeAttribute(Object attribute) { + + if (!containsKey(attribute)) { + return this; + } + + Hashtable newTable = new Hashtable(styleTable.size(), LOAD_FACTOR); + newTable.putAll(styleTable); + newTable.remove(attribute); + + return new AttributeMap(newTable, false); + } + + /** + * Return a AttributeMap with the entries of this AttributeMap whose + * attributes are not in the Set. + */ + public AttributeMap removeAttributes(AttributeSet attributes) { + + Set set = attributes; + return removeAttributes(set); + } + + /** + * Return a AttributeMap with the entries of this AttributeMap whose + * attributes are not in the Set. + */ + public AttributeMap removeAttributes(Set attributes) { + + // Create newTable on demand; if null at + // end of iteration then return this set. + // Should we intersect styleTable.keySet with + // attributes instead? + + Hashtable newTable = null; + Iterator attrIter = attributes.iterator(); + while (attrIter.hasNext()) { + Object current = attrIter.next(); + if (current != null && styleTable.containsKey(current)) { + if (newTable == null) { + newTable = new Hashtable(styleTable.size(), LOAD_FACTOR); + newTable.putAll(styleTable); + } + newTable.remove(current); + } + } + + if (newTable != null) { + return new AttributeMap(newTable, false); + } + else { + return this; + } + } + + /** + * Return a AttributeMap with the keys of this AttributeMap which + * are also in the Set. The set must not contain null. + */ + public AttributeMap intersectWith(AttributeSet attributes) { + + Set set = attributes; + return intersectWith(set); + } + + /** + * Return a AttributeMap with the keys of this AttributeMap which + * are also in the Set. The set must not contain null. + */ + public AttributeMap intersectWith(Set attributes) { + + // For now, forget about optimizing for the case when + // the return value is equivalent to this set. + + int attrSize = attributes.size(); + int styleTableSize = styleTable.size(); + int size = Math.min(attrSize, styleTableSize); + Hashtable newTable = new Hashtable(size, LOAD_FACTOR); + + if (attrSize < styleTableSize) { + Iterator attrIter = attributes.iterator(); + while (attrIter.hasNext()) { + Object current = attrIter.next(); + if (current != null) { + Object value = styleTable.get(current); + if (value != null) { + newTable.put(current, value); + } + } + } + } + else { + Iterator attrIter = keySet().iterator(); + while (attrIter.hasNext()) { + Object current = attrIter.next(); + if (attributes.contains(current)) { + newTable.put(current, styleTable.get(current)); + } + } + } + + return new AttributeMap(newTable, false); + } + + /** + * Put all entries in this AttributeMap into the given Map. + * @param rhs the Map into which entries are placed + */ + public void putAllInto(java.util.Map rhs) { + + rhs.putAll(this); + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/richtext/textlayout/attributes/AttributeSet.java b/icu4j/src/com/ibm/richtext/textlayout/attributes/AttributeSet.java new file mode 100755 index 00000000000..bc384250cca --- /dev/null +++ b/icu4j/src/com/ibm/richtext/textlayout/attributes/AttributeSet.java @@ -0,0 +1,345 @@ +/* + * @(#)$RCSfile: AttributeSet.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:33:31 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +// Requires Java2 +package com.ibm.textlayout.attributes; + +import java.util.Hashtable; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Set; +import java.util.Collection; + +/** + * An AttributeSet is an immutable collection of unique Objects. + * It has several operations + * which return new AttributeSet instances. + */ +public final class AttributeSet implements Set { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + + /** + * An AttributeSet with no members. + */ + public static final AttributeSet EMPTY_SET = new AttributeSet(); + + private Hashtable elements; + + private static final String errString = "AttributeSet is immutable."; + + private AttributeSet(Hashtable elements) { + + this.elements = elements; + } + + /** + * Package only. For AttributeMap use. + */ + static AttributeSet createKeySet(Hashtable hashtable) { + + Hashtable newElements = new Hashtable(); + + Enumeration e = hashtable.keys(); + while (e.hasMoreElements()) { + Object next = e.nextElement(); + newElements.put(next, next); + } + + return new AttributeSet(newElements); + } + + /** + * Create a new, empty AttributeSet. The set is semantically + * equivalent to EMPTY_SET. + */ + public AttributeSet() { + + elements = new Hashtable(); + } + + /** + * Create a new AttributeSet with the single element elem. + */ + public AttributeSet(Object elem) { + + elements = new Hashtable(1, 1); + elements.put(elem, elem); + } + + /** + * Create a new AttributeSet containing the items in the array elems. + */ + public AttributeSet(Object[] elems) { + + elements = new Hashtable(elems.length, 1); + for (int i=0; i < elems.length; i++) { + Object next = elems[i]; + elements.put(next, next); + } + } + + /** + * Return true if the number of elements in this set is 0. + * @return true if the number of elements in this set is 0 + */ + public boolean isEmpty() { + + return elements.isEmpty(); + } + + /** + * Return the number of elements in this set. + * @return the number of elements in this set + */ + public int size() { + + return elements.size(); + } + + public boolean equals(Object rhs) { + + try { + return equals((AttributeSet) rhs); + } + catch(ClassCastException e) { + return false; + } + } + + public boolean equals(AttributeSet rhs) { + + if (rhs == null) { + return false; + } + + return elements.equals(rhs.elements); + } + + /** + * Return true if this set contains the given Object + * @return true if this set contains o + */ + public boolean contains(Object o) { + + Object value = elements.get(o); + return value != null; + } + + /** + * Return true if this set contains all elements in the given + * Collection + * @param coll the collection to compare with + * @return true if this set contains all elements in the given + * Collection + */ + public boolean containsAll(Collection coll) { + + return elements.keySet().containsAll(coll); + } + + /** + * Return an Enumeration of the elements in this set. + * @return an Enumeration of the elements in this set + */ + public Enumeration elements() { + + return elements.keys(); + } + + /** + * Return an Iterator with the elements in this set. + * @return an Iterator with the elements in this set. + * The Iterator cannot be used to modify this AttributeSet. + */ + public Iterator iterator() { + + return new EnumerationIterator(elements.keys()); + } + + /** + * Fill in the given array with the elements in this set. + * @param storage an array to fill with this set's elements. + * The array cannot be null. + * @return the storage array. + */ + public Object[] toArray(Object[] storage) { + + Enumeration keys = elements.keys(); + int n=0; + while (keys.hasMoreElements()) { + storage[n++] = keys.nextElement(); + } + return storage; + } + + /** + * Return an array with the elements in this set. + * @return an array with the elements in this set + */ + public Object[] toArray() { + + return toArray(new Object[size()]); + } + + /** + * Throws UnsupportedOperationException. + * @see #addElement + * @throws UnsupportedOperationException + */ + public boolean add(Object o){ + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @throws UnsupportedOperationException + */ + public boolean remove(Object o) { + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #unionWith + * @throws UnsupportedOperationException + */ + public boolean addAll(Collection coll) { + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #subtract + * @throws UnsupportedOperationException + */ + public boolean removeAll(Collection coll) { + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #intersectWith + * @throws UnsupportedOperationException + */ + public boolean retainAll(Collection coll) { + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #EMPTY_SET + * @throws UnsupportedOperationException + */ + public void clear() { + throw new UnsupportedOperationException(errString); + } + + /** + * Return an AttributeSet containing the elements of this set + * and the given element + * @param element the element to add + * @return an AttributeSet like this one, with element + * added + */ + public AttributeSet addElement(Object element) { + + Hashtable newElements = (Hashtable) elements.clone(); + newElements.put(element, element); + return new AttributeSet(newElements); + } + + /** + * Return an AttributeSet which is the union of + * this set with the given set. + * @param s the set to union with + * @return an AttributeSet of the elements in this set or + * in s + */ + public AttributeSet unionWith(AttributeSet s) { + + Hashtable newElements = (Hashtable) elements.clone(); + + Iterator iter = s.iterator(); + while (iter.hasNext()) { + Object next = iter.next(); + newElements.put(next, next); + } + + return new AttributeSet(newElements); + } + + /** + * Return an AttributeSet which is the intersection of + * this set with the given set. + * @param s the set to intersect with + * @return an AttributeSet of the elements in this set which + * are in s + */ + public AttributeSet intersectWith(AttributeSet s) { + + Hashtable newElements = new Hashtable(); + + Iterator iter = s.iterator(); + while (iter.hasNext()) { + Object next = iter.next(); + if (elements.get(next) != null) { + newElements.put(next, next); + } + } + + return new AttributeSet(newElements); + } + + /** + * Return an AttributeSet with the elements in this set which + * are not in the given set. + * @param s the set of elements to exclude + * @return an AttributeSet of the elements in this set which + * are not in s + */ + public AttributeSet subtract(AttributeSet s) { + + Hashtable newElements = (Hashtable) elements.clone(); + + Iterator iter = s.iterator(); + while (iter.hasNext()) { + newElements.remove(iter.next()); + } + + return new AttributeSet(newElements); + } + + private static final class EnumerationIterator implements Iterator { + + private Enumeration e; + + EnumerationIterator(Enumeration e) { + this.e = e; + } + + public boolean hasNext() { + return e.hasMoreElements(); + } + + public Object next() { + return e.nextElement(); + } + + public void remove() { + throw new UnsupportedOperationException(errString); + } + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/textlayout/attributes/AttributeMap.java b/icu4j/src/com/ibm/textlayout/attributes/AttributeMap.java new file mode 100755 index 00000000000..c8239288ede --- /dev/null +++ b/icu4j/src/com/ibm/textlayout/attributes/AttributeMap.java @@ -0,0 +1,529 @@ +/* + * @(#)$RCSfile: AttributeMap.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:33:31 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +// Requires Java2 +package com.ibm.textlayout.attributes; + +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Set; + +import java.io.Externalizable; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.IOException; + + +/** + * AttributeMap is an immutable Map. Additionally, there are + * several methods for common operations (union, + * remove, intersect); these methods return new AttributeMap + * instances. + *

+ * Although any non-null Object can be a key or value in an + * AttributeMap, typically the keys are fields of TextAttribute. + * @see TextAttribute + */ +public final class AttributeMap implements java.util.Map, + com.ibm.textlayout.attributes.Map, + Externalizable { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + private static final int CURRENT_VERSION = 1; + + private static final long serialVersionUID = 9510803; + + private static final String errString = "StyleSets are immutable."; + + // This is passed to the Hashtable constructor as the + // load factor argument. It is chosen to avoid resizing + // the Hashtable whenever possible. I think that 1 + // does this. + private static final int LOAD_FACTOR = 1; + + private Hashtable styleTable; + private transient AttributeSet cachedKeySet = null; + private transient Collection cachedValueCollection = null; + private transient Set cachedEntrySet = null; + + /** + * An empty AttributeMap. + */ + public static final AttributeMap EMPTY_ATTRIBUTE_MAP = new AttributeMap(); + +// ============== +// Constructors +// ============== + + /** + * Create a new, empty AttributeMap. EMPTY_STYLE_SET can be used + * in place of an AttributeMap produced by this constructor. + */ + public AttributeMap() { + + styleTable = new Hashtable(1, LOAD_FACTOR); + } + + /** + * Create an AttributeMap with the same key-value + * entries as the given Map. + * @param map a Map whose key-value entries will + * become the entries for this AttributeMap. map + * is not modified, and must not contain null keys or values. + */ + public AttributeMap(java.util.Map map) { + + styleTable = new Hashtable(map.size(), LOAD_FACTOR); + styleTable.putAll(map); + } + + /** + * Create an AttributeMap with the same key-value + * entries as the given Hashtable. + * @param table a Hashtable whose key-value entries will + * become the entries for this AttributeMap. table + * is not modified. + */ + public AttributeMap(Hashtable hashtable) { + + this((java.util.Map) hashtable); + } + + /** + * Create an AttributeMap with a single entry of + * {attribute, value}. + * @param attribute the key in this AttributeMap's single entry + * @param value the value in this AttributeMap's single entry + */ + public AttributeMap(Object key, Object value) { + + styleTable = new Hashtable(1, LOAD_FACTOR); + + // hashtable checks value for null + styleTable.put(key, value); + } + + // For internal use only. + private AttributeMap(Hashtable table, boolean clone) { + + if (clone) { + styleTable = (Hashtable) table.clone(); + } + else { + this.styleTable = table; + } + } + + public void writeExternal(ObjectOutput out) throws IOException { + + out.writeInt(CURRENT_VERSION); + out.writeInt(styleTable.size()); + Enumeration e = styleTable.keys(); + while (e.hasMoreElements()) { + Object key = e.nextElement(); + out.writeObject(AttributeKey.mapAttributeToKey(key)); + out.writeObject(styleTable.get(key)); + } + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + + if (in.readInt() != CURRENT_VERSION) { + throw new IOException("Invalid version of StyleBuffer"); + } + + int count = in.readInt(); + for (int i=0; i < count; i += 1) { + Object key = AttributeKey.mapKeyToAttribute(in.readObject()); + Object value = in.readObject(); + styleTable.put(key, value); + } + } + +// ============== +// Map interface +// ============== + +// queries + /** + * Return the number of entries in the AttributeMap. + * @return the number of entries in the AttributeMap + */ + public int size() { + + return styleTable.size(); + } + + /** + * Return true if the number of entries in the AttributeMap + * is 0. + * @return true if the number of entries in the AttributeMap + * is 0 + */ + public boolean isEmpty() { + + return styleTable.isEmpty(); + } + + /** + * Return true if the given key is in this AttributeMap. + * @param key the key to test + * @return true if key is in this AttributeMap + */ + public boolean containsKey(Object key) { + + return styleTable.containsKey(key); + } + + /** + * Return true if the given value is in this AttributeMap. + * @param key the value to test + * @return true if value is in this AttributeMap + */ + public boolean containsValue(Object value) { + + return styleTable.containsValue(value); + } + + /** + * Return the value associated with the given key. If the + * key is not in this AttributeMap null is returned. + * @param key the key to look up + * @return the value associated with key, or + * null if key is not in this AttributeMap + */ + public Object get(Object key) { + + return styleTable.get(key); + } + +// modifiers - all throw exceptions + + /** + * Throws UnsupportedOperationException. + * @see #addAttribute + * @throws UnsupportedOperationException + */ + public Object put(Object key, Object value) { + + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #removeAttributes + * @throws UnsupportedOperationException + */ + public Object remove(Object key) { + + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #addAttributes + * @throws UnsupportedOperationException + */ + public void putAll(java.util.Map t) { + + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #EMPTY_ATTRIBUTE_MAP + * @throws UnsupportedOperationException + */ + public void clear() { + + throw new UnsupportedOperationException(errString); + } + +// views + + /** + * Return an AttributeSet containing every key in this AttributeMap. + * @return an AttributeSet containing every key in this AttributeMap + */ + public Set keySet() { + + return getKeySet(); + } + + /** + * Return an AttributeSet containing every key in this AttributeMap. + * @return an AttributeSet containing every key in this AttributeMap + */ + public AttributeSet getKeySet() { + + AttributeSet result = cachedKeySet; + + if (result == null) { + result = AttributeSet.createKeySet(styleTable); + cachedKeySet = result; + } + + return result; + } + + /** + * Return a Collection containing every value in this AttributeMap. + * @return a Collection containing every value in this AttributeMap + */ + public Collection values() { + + Collection result = cachedValueCollection; + + if (result == null) { + result = Collections.unmodifiableCollection(styleTable.values()); + cachedValueCollection = result; + } + + return result; + } + + /** + * Return a Set containing all entries in this AttributeMap. + */ + public Set entrySet() { + + Set result = cachedEntrySet; + + if (result == null) { + result = Collections.unmodifiableSet(styleTable.entrySet()); + cachedEntrySet = result; + } + + return result; + } + + public boolean equals(Object rhs) { + + if (rhs == this) { + return true; + } + + if (rhs == null) { + return false; + } + + AttributeMap rhsStyleSet = null; + + try { + rhsStyleSet = (AttributeMap) rhs; + } + catch(ClassCastException e) { + return false; + } + + return styleTable.equals(rhsStyleSet.styleTable); + } + + public int hashCode() { + + return styleTable.hashCode(); + } + + public String toString() { + + return styleTable.toString(); + } + +// ============== +// Operations +// ============== + + /** + * Return a AttributeMap which contains entries in this AttributeMap, + * along with an entry for . If attribute + * is already present in this AttributeMap its value becomes value. + */ + public AttributeMap addAttribute(Object key, Object value) { + + // try to optimize for case where is already there? + Hashtable newTable = new Hashtable(styleTable.size() + 1, LOAD_FACTOR); + newTable.putAll(styleTable); + newTable.put(key, value); + return new AttributeMap(newTable, false); + } + + /** + * Return a AttributeMap which contains entries in this AttributeMap + * and in rhs. If an attribute appears in both StyleSets the + * value from rhs is used. + */ + public AttributeMap addAttributes(AttributeMap rhs) { + + int thisSize = size(); + + if (thisSize == 0) { + return rhs; + } + + int otherSize = rhs.size(); + + if (otherSize == 0) { + return this; + } + + Hashtable newTable = new Hashtable(thisSize + otherSize, LOAD_FACTOR); + + newTable.putAll(styleTable); + newTable.putAll(rhs); + + return new AttributeMap(newTable, false); + } + + /** + * Return a AttributeMap which contains entries in this AttributeMap + * and in rhs. If an attribute appears in both StyleSets the + * value from rhs is used. + * The Map's keys and values must be non-null. + */ + public AttributeMap addAttributes(java.util.Map rhs) { + + if (rhs instanceof AttributeMap) { + return addAttributes((AttributeMap)rhs); + } + + Hashtable newTable = new Hashtable(size() + rhs.size(), LOAD_FACTOR); + + newTable.putAll(styleTable); + newTable.putAll(rhs); + + return new AttributeMap(newTable, false); + } + + /** + * Return a AttributeMap with the entries in this AttributeMap, but + * without attribute as a key. + */ + public AttributeMap removeAttribute(Object attribute) { + + if (!containsKey(attribute)) { + return this; + } + + Hashtable newTable = new Hashtable(styleTable.size(), LOAD_FACTOR); + newTable.putAll(styleTable); + newTable.remove(attribute); + + return new AttributeMap(newTable, false); + } + + /** + * Return a AttributeMap with the entries of this AttributeMap whose + * attributes are not in the Set. + */ + public AttributeMap removeAttributes(AttributeSet attributes) { + + Set set = attributes; + return removeAttributes(set); + } + + /** + * Return a AttributeMap with the entries of this AttributeMap whose + * attributes are not in the Set. + */ + public AttributeMap removeAttributes(Set attributes) { + + // Create newTable on demand; if null at + // end of iteration then return this set. + // Should we intersect styleTable.keySet with + // attributes instead? + + Hashtable newTable = null; + Iterator attrIter = attributes.iterator(); + while (attrIter.hasNext()) { + Object current = attrIter.next(); + if (current != null && styleTable.containsKey(current)) { + if (newTable == null) { + newTable = new Hashtable(styleTable.size(), LOAD_FACTOR); + newTable.putAll(styleTable); + } + newTable.remove(current); + } + } + + if (newTable != null) { + return new AttributeMap(newTable, false); + } + else { + return this; + } + } + + /** + * Return a AttributeMap with the keys of this AttributeMap which + * are also in the Set. The set must not contain null. + */ + public AttributeMap intersectWith(AttributeSet attributes) { + + Set set = attributes; + return intersectWith(set); + } + + /** + * Return a AttributeMap with the keys of this AttributeMap which + * are also in the Set. The set must not contain null. + */ + public AttributeMap intersectWith(Set attributes) { + + // For now, forget about optimizing for the case when + // the return value is equivalent to this set. + + int attrSize = attributes.size(); + int styleTableSize = styleTable.size(); + int size = Math.min(attrSize, styleTableSize); + Hashtable newTable = new Hashtable(size, LOAD_FACTOR); + + if (attrSize < styleTableSize) { + Iterator attrIter = attributes.iterator(); + while (attrIter.hasNext()) { + Object current = attrIter.next(); + if (current != null) { + Object value = styleTable.get(current); + if (value != null) { + newTable.put(current, value); + } + } + } + } + else { + Iterator attrIter = keySet().iterator(); + while (attrIter.hasNext()) { + Object current = attrIter.next(); + if (attributes.contains(current)) { + newTable.put(current, styleTable.get(current)); + } + } + } + + return new AttributeMap(newTable, false); + } + + /** + * Put all entries in this AttributeMap into the given Map. + * @param rhs the Map into which entries are placed + */ + public void putAllInto(java.util.Map rhs) { + + rhs.putAll(this); + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/textlayout/attributes/AttributeSet.java b/icu4j/src/com/ibm/textlayout/attributes/AttributeSet.java new file mode 100755 index 00000000000..bc384250cca --- /dev/null +++ b/icu4j/src/com/ibm/textlayout/attributes/AttributeSet.java @@ -0,0 +1,345 @@ +/* + * @(#)$RCSfile: AttributeSet.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:33:31 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +// Requires Java2 +package com.ibm.textlayout.attributes; + +import java.util.Hashtable; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Set; +import java.util.Collection; + +/** + * An AttributeSet is an immutable collection of unique Objects. + * It has several operations + * which return new AttributeSet instances. + */ +public final class AttributeSet implements Set { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + + /** + * An AttributeSet with no members. + */ + public static final AttributeSet EMPTY_SET = new AttributeSet(); + + private Hashtable elements; + + private static final String errString = "AttributeSet is immutable."; + + private AttributeSet(Hashtable elements) { + + this.elements = elements; + } + + /** + * Package only. For AttributeMap use. + */ + static AttributeSet createKeySet(Hashtable hashtable) { + + Hashtable newElements = new Hashtable(); + + Enumeration e = hashtable.keys(); + while (e.hasMoreElements()) { + Object next = e.nextElement(); + newElements.put(next, next); + } + + return new AttributeSet(newElements); + } + + /** + * Create a new, empty AttributeSet. The set is semantically + * equivalent to EMPTY_SET. + */ + public AttributeSet() { + + elements = new Hashtable(); + } + + /** + * Create a new AttributeSet with the single element elem. + */ + public AttributeSet(Object elem) { + + elements = new Hashtable(1, 1); + elements.put(elem, elem); + } + + /** + * Create a new AttributeSet containing the items in the array elems. + */ + public AttributeSet(Object[] elems) { + + elements = new Hashtable(elems.length, 1); + for (int i=0; i < elems.length; i++) { + Object next = elems[i]; + elements.put(next, next); + } + } + + /** + * Return true if the number of elements in this set is 0. + * @return true if the number of elements in this set is 0 + */ + public boolean isEmpty() { + + return elements.isEmpty(); + } + + /** + * Return the number of elements in this set. + * @return the number of elements in this set + */ + public int size() { + + return elements.size(); + } + + public boolean equals(Object rhs) { + + try { + return equals((AttributeSet) rhs); + } + catch(ClassCastException e) { + return false; + } + } + + public boolean equals(AttributeSet rhs) { + + if (rhs == null) { + return false; + } + + return elements.equals(rhs.elements); + } + + /** + * Return true if this set contains the given Object + * @return true if this set contains o + */ + public boolean contains(Object o) { + + Object value = elements.get(o); + return value != null; + } + + /** + * Return true if this set contains all elements in the given + * Collection + * @param coll the collection to compare with + * @return true if this set contains all elements in the given + * Collection + */ + public boolean containsAll(Collection coll) { + + return elements.keySet().containsAll(coll); + } + + /** + * Return an Enumeration of the elements in this set. + * @return an Enumeration of the elements in this set + */ + public Enumeration elements() { + + return elements.keys(); + } + + /** + * Return an Iterator with the elements in this set. + * @return an Iterator with the elements in this set. + * The Iterator cannot be used to modify this AttributeSet. + */ + public Iterator iterator() { + + return new EnumerationIterator(elements.keys()); + } + + /** + * Fill in the given array with the elements in this set. + * @param storage an array to fill with this set's elements. + * The array cannot be null. + * @return the storage array. + */ + public Object[] toArray(Object[] storage) { + + Enumeration keys = elements.keys(); + int n=0; + while (keys.hasMoreElements()) { + storage[n++] = keys.nextElement(); + } + return storage; + } + + /** + * Return an array with the elements in this set. + * @return an array with the elements in this set + */ + public Object[] toArray() { + + return toArray(new Object[size()]); + } + + /** + * Throws UnsupportedOperationException. + * @see #addElement + * @throws UnsupportedOperationException + */ + public boolean add(Object o){ + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @throws UnsupportedOperationException + */ + public boolean remove(Object o) { + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #unionWith + * @throws UnsupportedOperationException + */ + public boolean addAll(Collection coll) { + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #subtract + * @throws UnsupportedOperationException + */ + public boolean removeAll(Collection coll) { + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #intersectWith + * @throws UnsupportedOperationException + */ + public boolean retainAll(Collection coll) { + throw new UnsupportedOperationException(errString); + } + + /** + * Throws UnsupportedOperationException. + * @see #EMPTY_SET + * @throws UnsupportedOperationException + */ + public void clear() { + throw new UnsupportedOperationException(errString); + } + + /** + * Return an AttributeSet containing the elements of this set + * and the given element + * @param element the element to add + * @return an AttributeSet like this one, with element + * added + */ + public AttributeSet addElement(Object element) { + + Hashtable newElements = (Hashtable) elements.clone(); + newElements.put(element, element); + return new AttributeSet(newElements); + } + + /** + * Return an AttributeSet which is the union of + * this set with the given set. + * @param s the set to union with + * @return an AttributeSet of the elements in this set or + * in s + */ + public AttributeSet unionWith(AttributeSet s) { + + Hashtable newElements = (Hashtable) elements.clone(); + + Iterator iter = s.iterator(); + while (iter.hasNext()) { + Object next = iter.next(); + newElements.put(next, next); + } + + return new AttributeSet(newElements); + } + + /** + * Return an AttributeSet which is the intersection of + * this set with the given set. + * @param s the set to intersect with + * @return an AttributeSet of the elements in this set which + * are in s + */ + public AttributeSet intersectWith(AttributeSet s) { + + Hashtable newElements = new Hashtable(); + + Iterator iter = s.iterator(); + while (iter.hasNext()) { + Object next = iter.next(); + if (elements.get(next) != null) { + newElements.put(next, next); + } + } + + return new AttributeSet(newElements); + } + + /** + * Return an AttributeSet with the elements in this set which + * are not in the given set. + * @param s the set of elements to exclude + * @return an AttributeSet of the elements in this set which + * are not in s + */ + public AttributeSet subtract(AttributeSet s) { + + Hashtable newElements = (Hashtable) elements.clone(); + + Iterator iter = s.iterator(); + while (iter.hasNext()) { + newElements.remove(iter.next()); + } + + return new AttributeSet(newElements); + } + + private static final class EnumerationIterator implements Iterator { + + private Enumeration e; + + EnumerationIterator(Enumeration e) { + this.e = e; + } + + public boolean hasNext() { + return e.hasMoreElements(); + } + + public Object next() { + return e.nextElement(); + } + + public void remove() { + throw new UnsupportedOperationException(errString); + } + } +} \ No newline at end of file