1 /* 2 ******************************************************************************* 3 * Copyright (C) 2007, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7 package com.ibm.icu.dev.test.util; 8 9 import com.ibm.icu.impl.Utility; 10 11 /** 12 * @author srl 13 * 14 * analog of FieldsSet in C++ 15 */ 16 public class FieldsSet { 17 public static final int NO_ENUM = -1; 18 FieldsSet(int whichEnum, int fieldsCount)19 protected FieldsSet(int whichEnum, int fieldsCount) { 20 if (fieldsCount <= 0 && whichEnum != NO_ENUM) { 21 fieldsCount = DebugUtilities.enumCount(whichEnum); 22 } 23 fEnum = whichEnum; 24 fFieldsCount = fieldsCount; 25 if(fieldsCount<0) { 26 throw new InternalError("Preposterous field count " + fieldsCount); 27 } 28 fValues = new int[fFieldsCount]; 29 fIsSet = new boolean[fFieldsCount]; 30 clear(); 31 } 32 33 protected int fEnum = NO_ENUM; 34 35 protected int fFieldsCount = 0; 36 37 protected int fValues[] = null; 38 39 protected boolean fIsSet[] = null; 40 clear()41 public void clear() { 42 for (int i = 0; i < fFieldsCount; i++) { 43 clear(i); 44 } 45 } 46 clear(int field)47 public void clear(int field) { 48 fValues[field] = -1; 49 fIsSet[field] = false; 50 } 51 set(int field, int amount)52 public void set(int field, int amount) { 53 fValues[field] = amount; 54 fIsSet[field] = true; 55 } 56 isSet(int field)57 public boolean isSet(int field) { 58 return fIsSet[field]; 59 } 60 get(int field)61 public int get(int field) { 62 if (fIsSet[field]) { 63 return fValues[field]; 64 } else { 65 return -1; 66 } 67 } 68 isSameType(FieldsSet other)69 public boolean isSameType(FieldsSet other) { 70 return ((other.fEnum == fEnum) && (other.fFieldsCount == fFieldsCount)); 71 } 72 fieldCount()73 public int fieldCount() { 74 return fFieldsCount; 75 } 76 77 /** 78 * @param other "expected" set to match against 79 * @return a formatted string listing which fields are set in this, with the 80 * comparison made agaainst those fields in other, or, 'null' if there is no difference. 81 */ diffFrom(FieldsSet other)82 public String diffFrom(FieldsSet other) { 83 StringBuffer str = new StringBuffer(); 84 if(!isSameType(other)) { 85 throw new IllegalArgumentException("U_ILLEGAL_ARGUMENT_ERROR: FieldsSet of a different type!"); 86 } 87 for (int i=0; i<fieldCount(); i++) { 88 if (isSet(i)) { 89 int myVal = get(i); 90 int theirVal = other.get(i); 91 92 if(fEnum != NO_ENUM) { 93 String fieldName = DebugUtilities.enumString(fEnum, i); 94 95 String aval = Integer.toString(myVal); 96 String bval = Integer.toString(theirVal); 97 98 str.append(fieldName +"="+aval+" not "+bval+", "); 99 } else { 100 str.append(Integer.toString(i) + "=" + myVal+" not " + theirVal+", "); 101 } 102 } 103 } 104 if(str.length()==0) { 105 return null; 106 } 107 return str.toString(); 108 } 109 110 /** 111 * @param str string to parse 112 * @param status formatted string for status 113 */ parseFrom(String str)114 public int parseFrom(String str) { 115 return parseFrom(str, null); 116 } 117 parseFrom(String str, FieldsSet inheritFrom)118 public int parseFrom(String str, FieldsSet inheritFrom) { 119 int goodFields = 0; 120 121 String[] fields = Utility.split(str, ','); 122 for(int i=0;i<fields.length;i++) { 123 String fieldStr = fields[i]; 124 String kv[] = Utility.split(fieldStr, '='); 125 if(kv.length < 1 || kv.length > 2) { 126 throw new InternalError("split around '=' failed: " + fieldStr); 127 } 128 String key = kv[0]; 129 String value = ""; 130 if(kv.length>1) { 131 value = kv[1]; 132 } 133 134 int field = handleParseName(inheritFrom, key, value); 135 if(field != -1) { 136 handleParseValue(inheritFrom, field, value); 137 goodFields++; 138 } 139 } 140 141 return goodFields; 142 } 143 144 /** 145 * Callback interface for subclass. This function is called when parsing a 146 * field name, such as "MONTH" in "MONTH=4". Base implementation is to 147 * lookup the enum value using udbg_* utilities, or else as an integer if 148 * enum is not available. 149 * 150 * If there is a special directive, the implementer can catch it here and 151 * return -1 after special processing completes. 152 * 153 * @param inheritFrom the set inheriting from - may be null. 154 * @param name the field name (key side) 155 * @param substr the string in question (value side) 156 * @param status error status - set to error for failure. 157 * @return field number, or negative if field should be skipped. 158 */ handleParseName(FieldsSet inheritFrom, String name, String substr)159 protected int handleParseName(FieldsSet inheritFrom, String name, 160 String substr) { 161 int field = -1; 162 if(fEnum != NO_ENUM) { 163 field = DebugUtilities.enumByString(fEnum, name); 164 } 165 if(field < 0) { 166 field = Integer.parseInt(name); 167 } 168 return field; 169 } 170 171 /** 172 * Callback interface for subclass. Base implementation is to call 173 * parseValueDefault(...) 174 * 175 * @param inheritFrom the set inheriting from - may be null. 176 * @param field which field is being parsed 177 * @param substr the string in question (value side) 178 * @param status error status - set to error for failure. 179 * @see parseValueDefault 180 */ handleParseValue(FieldsSet inheritFrom, int field, String substr)181 protected void handleParseValue(FieldsSet inheritFrom, int field, 182 String substr) { 183 parseValueDefault(inheritFrom, field, substr); 184 } 185 186 /** 187 * the default implementation for handleParseValue. Base implementation is 188 * to parse a decimal integer value, or inherit from inheritFrom if the 189 * string is 0-length. Implementations of this function should call 190 * set(field,...) on successful parse. 191 * 192 * @see handleParseValue 193 */ parseValueDefault(FieldsSet inheritFrom, int field, String substr)194 protected void parseValueDefault(FieldsSet inheritFrom, int field, 195 String substr) { 196 if(substr.length()==0) { 197 if(inheritFrom == null) { 198 throw new InternalError("Trying to inherit from field " + field + " but inheritFrom is null"); 199 } 200 if(!inheritFrom.isSet(field)) { 201 throw new InternalError("Trying to inherit from field " + field + " but inheritFrom["+field+"] is not set"); 202 } 203 set(field,inheritFrom.get(field)); 204 } else { 205 int value = Integer.parseInt(substr); 206 set(field, value); 207 } 208 } 209 210 /** 211 * convenience implementation for handleParseValue attempt to load a value 212 * from an enum value using udbg_enumByString() if fails, will call 213 * parseValueDefault() 214 * 215 * @see handleParseValue 216 */ parseValueEnum(int type, FieldsSet inheritFrom, int field, String substr)217 protected void parseValueEnum(int type, FieldsSet inheritFrom, int field, 218 String substr) { 219 int value = DebugUtilities.enumByString(type, substr); 220 if(value>=0) { 221 set(field,value); 222 return; 223 } 224 parseValueDefault(inheritFrom, field, substr); 225 } 226 fieldName(int field)227 public String fieldName(int field) { 228 return (fEnum!=NO_ENUM)?DebugUtilities.enumString(fEnum, field):Integer.toString(field); 229 } 230 toString()231 public String toString() { 232 String str = getClass().getName()+" ["+fFieldsCount+"," 233 +(fEnum!=NO_ENUM?DebugUtilities.typeString(fEnum):Integer.toString(fEnum))+"]: "; 234 for(int i=0;i<fFieldsCount;i++) { 235 if(isSet(i)) { 236 str = str + fieldName(i)+"="+get(i)+","; 237 } 238 } 239 return str; 240 } 241 } 242