00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <boost/lexical_cast.hpp>
00021 #include <boost/static_assert.hpp>
00022 #include <pion/platform/Comparison.hpp>
00023 #include <unicode/coll.h>
00024 #include <unicode/ustring.h>
00025 #include <unicode/stsearch.h>
00026
00027
00028 namespace pion {
00029 namespace platform {
00030
00031
00032 struct comparison_info {
00033 Comparison::ComparisonType type;
00034 const char* name;
00035 boost::uint8_t arity;
00036 bool is_generic;
00037 bool applies_to_numeric_terms;
00038 bool applies_to_string_terms;
00039 bool applies_to_date_time_terms;
00040 bool applies_to_date_terms;
00041 bool applies_to_time_terms;
00042 };
00043
00044 const comparison_info comparison_table[] = {
00045 { Comparison::TYPE_FALSE, "false", 1, true, true, true, true, true, true },
00046 { Comparison::TYPE_TRUE, "true", 1, true, true, true, true, true, true },
00047 { Comparison::TYPE_IS_DEFINED, "is-defined", 1, true, true, true, true, true, true },
00048 { Comparison::TYPE_IS_NOT_DEFINED, "is-not-defined", 1, true, true, true, true, true, true },
00049
00050 { Comparison::TYPE_EQUALS, "equals", 2, false, true, false, false, false, false },
00051 { Comparison::TYPE_NOT_EQUALS, "not-equals", 2, false, true, false, false, false, false },
00052 { Comparison::TYPE_GREATER_THAN, "greater-than", 2, false, true, false, false, false, false },
00053 { Comparison::TYPE_LESS_THAN, "less-than", 2, false, true, false, false, false, false },
00054 { Comparison::TYPE_GREATER_OR_EQUAL, "greater-or-equal", 2, false, true, false, false, false, false },
00055 { Comparison::TYPE_LESS_OR_EQUAL, "less-or-equal", 2, false, true, false, false, false, false },
00056
00057 { Comparison::TYPE_EXACT_MATCH, "exact-match", 2, false, false, true, false, false, false },
00058 { Comparison::TYPE_NOT_EXACT_MATCH, "not-exact-match", 2, false, false, true, false, false, false },
00059 { Comparison::TYPE_CONTAINS, "contains", 2, false, false, true, false, false, false },
00060 { Comparison::TYPE_NOT_CONTAINS, "not-contains", 2, false, false, true, false, false, false },
00061 { Comparison::TYPE_STARTS_WITH, "starts-with", 2, false, false, true, false, false, false },
00062 { Comparison::TYPE_NOT_STARTS_WITH, "not-starts-with", 2, false, false, true, false, false, false },
00063 { Comparison::TYPE_ENDS_WITH, "ends-with", 2, false, false, true, false, false, false },
00064 { Comparison::TYPE_NOT_ENDS_WITH, "not-ends-with", 2, false, false, true, false, false, false },
00065 { Comparison::TYPE_ORDERED_BEFORE, "ordered-before", 2, false, false, true, false, false, false },
00066 { Comparison::TYPE_NOT_ORDERED_BEFORE, "not-ordered-before", 2, false, false, true, false, false, false },
00067 { Comparison::TYPE_ORDERED_AFTER, "ordered-after", 2, false, false, true, false, false, false },
00068 { Comparison::TYPE_NOT_ORDERED_AFTER, "not-ordered-after", 2, false, false, true, false, false, false },
00069 { Comparison::TYPE_REGEX, "regex", 2, false, false, true, false, false, false },
00070 { Comparison::TYPE_NOT_REGEX, "not-regex", 2, false, false, true, false, false, false },
00071
00072 { Comparison::TYPE_EXACT_MATCH_PRIMARY, "exact-match-primary", 2, false, false, true, false, false, false },
00073 { Comparison::TYPE_NOT_EXACT_MATCH_PRIMARY, "not-exact-match-primary", 2, false, false, true, false, false, false },
00074 { Comparison::TYPE_CONTAINS_PRIMARY, "contains-primary", 2, false, false, true, false, false, false },
00075 { Comparison::TYPE_NOT_CONTAINS_PRIMARY, "not-contains-primary", 2, false, false, true, false, false, false },
00076 { Comparison::TYPE_STARTS_WITH_PRIMARY, "starts-with-primary", 2, false, false, true, false, false, false },
00077 { Comparison::TYPE_NOT_STARTS_WITH_PRIMARY, "not-starts-with-primary", 2, false, false, true, false, false, false },
00078 { Comparison::TYPE_ENDS_WITH_PRIMARY, "ends-with-primary", 2, false, false, true, false, false, false },
00079 { Comparison::TYPE_NOT_ENDS_WITH_PRIMARY, "not-ends-with-primary", 2, false, false, true, false, false, false },
00080 { Comparison::TYPE_ORDERED_BEFORE_PRIMARY, "ordered-before-primary", 2, false, false, true, false, false, false },
00081 { Comparison::TYPE_NOT_ORDERED_BEFORE_PRIMARY,"not-ordered-before-primary",2, false, false, true, false, false, false },
00082 { Comparison::TYPE_ORDERED_AFTER_PRIMARY, "ordered-after-primary", 2, false, false, true, false, false, false },
00083 { Comparison::TYPE_NOT_ORDERED_AFTER_PRIMARY, "not-ordered-after-primary", 2, false, false, true, false, false, false },
00084
00085 { Comparison::TYPE_SAME_DATE_TIME, "same-date-time", 2, false, false, false, true, false, false },
00086 { Comparison::TYPE_NOT_SAME_DATE_TIME, "not-same-date-time", 2, false, false, false, true, false, false },
00087 { Comparison::TYPE_EARLIER_DATE_TIME, "earlier-date-time", 2, false, false, false, true, false, false },
00088 { Comparison::TYPE_LATER_DATE_TIME, "later-date-time", 2, false, false, false, true, false, false },
00089 { Comparison::TYPE_SAME_OR_EARLIER_DATE_TIME, "same-or-earlier-date-time", 2, false, false, false, true, false, false },
00090 { Comparison::TYPE_SAME_OR_LATER_DATE_TIME, "same-or-later-date-time", 2, false, false, false, true, false, false },
00091
00092 { Comparison::TYPE_SAME_DATE, "same-date", 2, false, false, false, true, true, false },
00093 { Comparison::TYPE_NOT_SAME_DATE, "not-same-date", 2, false, false, false, true, true, false },
00094 { Comparison::TYPE_EARLIER_DATE, "earlier-date", 2, false, false, false, true, true, false },
00095 { Comparison::TYPE_LATER_DATE, "later-date", 2, false, false, false, true, true, false },
00096 { Comparison::TYPE_SAME_OR_EARLIER_DATE, "same-or-earlier-date", 2, false, false, false, true, true, false },
00097 { Comparison::TYPE_SAME_OR_LATER_DATE, "same-or-later-date", 2, false, false, false, true, true, false },
00098
00099 { Comparison::TYPE_SAME_TIME, "same-time", 2, false, false, false, true, false, true },
00100 { Comparison::TYPE_NOT_SAME_TIME, "not-same-time", 2, false, false, false, true, false, true },
00101 { Comparison::TYPE_EARLIER_TIME, "earlier-time", 2, false, false, false, true, false, true },
00102 { Comparison::TYPE_LATER_TIME, "later-time", 2, false, false, false, true, false, true },
00103 { Comparison::TYPE_SAME_OR_EARLIER_TIME, "same-or-earlier-time", 2, false, false, false, true, false, true },
00104 { Comparison::TYPE_SAME_OR_LATER_TIME, "same-or-later-time", 2, false, false, false, true, false, true }
00105 };
00106
00107 BOOST_STATIC_ASSERT(sizeof(comparison_table) / sizeof(comparison_table[0]) - 1 == Comparison::LAST_COMPARISON_TYPE);
00108
00109
00110
00111
00112 bool Comparison::checkForValidType(const ComparisonType type) const
00113 {
00114 bool result = false;
00115
00116 if (comparison_table[type].is_generic) {
00117
00118 result = true;
00119 } else {
00120 switch (m_term.term_type) {
00121 case Vocabulary::TYPE_NULL:
00122 case Vocabulary::TYPE_OBJECT:
00123 result = false;
00124 break;
00125 case Vocabulary::TYPE_INT8:
00126 case Vocabulary::TYPE_UINT8:
00127 case Vocabulary::TYPE_INT16:
00128 case Vocabulary::TYPE_UINT16:
00129 case Vocabulary::TYPE_INT32:
00130 case Vocabulary::TYPE_UINT32:
00131 case Vocabulary::TYPE_INT64:
00132 case Vocabulary::TYPE_UINT64:
00133 case Vocabulary::TYPE_FLOAT:
00134 case Vocabulary::TYPE_DOUBLE:
00135 case Vocabulary::TYPE_LONG_DOUBLE:
00136 result = comparison_table[type].applies_to_numeric_terms;
00137 break;
00138 case Vocabulary::TYPE_SHORT_STRING:
00139 case Vocabulary::TYPE_STRING:
00140 case Vocabulary::TYPE_LONG_STRING:
00141 case Vocabulary::TYPE_CHAR:
00142 case Vocabulary::TYPE_BLOB:
00143 case Vocabulary::TYPE_ZBLOB:
00144 result = comparison_table[type].applies_to_string_terms;
00145 break;
00146 case Vocabulary::TYPE_DATE_TIME:
00147 result = comparison_table[type].applies_to_date_time_terms;
00148 break;
00149 case Vocabulary::TYPE_DATE:
00150 result = comparison_table[type].applies_to_date_terms;
00151 break;
00152 case Vocabulary::TYPE_TIME:
00153 result = comparison_table[type].applies_to_time_terms;
00154 break;
00155 }
00156 }
00157
00158 return result;
00159 }
00160
00161 void Comparison::configure(const ComparisonType type,
00162 const std::string & value,
00163 const bool match_all_values)
00164 {
00165 if (! checkForValidType(type))
00166 throw InvalidTypeForTermException();
00167
00168 if (! value.empty()) {
00169
00170 UErrorCode errorCode = U_ZERO_ERROR;
00171 u_strFromUTF8(NULL, 0, NULL, value.c_str(), -1, &errorCode);
00172 if (errorCode == U_INVALID_CHAR_FOUND)
00173 throw InvalidComparisonException();
00174 if (errorCode != U_BUFFER_OVERFLOW_ERROR)
00175 throw InvalidComparisonException();
00176
00177
00178 }
00179
00180 if (type == TYPE_REGEX || type == TYPE_NOT_REGEX) {
00181 m_regex = boost::make_u32regex(value);
00182 m_regex_str = value;
00183 } else if (comparison_table[type].applies_to_string_terms) {
00184 m_str_value = value;
00185
00186 switch (type) {
00187 case TYPE_EXACT_MATCH:
00188 case TYPE_NOT_EXACT_MATCH:
00189 m_comparison_func = boost::shared_ptr<ComparisonFunctor>(new CompareStringExactMatch(m_str_value));
00190 break;
00191 case TYPE_EXACT_MATCH_PRIMARY:
00192 case TYPE_NOT_EXACT_MATCH_PRIMARY:
00193 m_comparison_func = boost::shared_ptr<ComparisonFunctor>(new CompareStringExactMatch(m_str_value, UCOL_PRIMARY));
00194 break;
00195 case TYPE_CONTAINS:
00196 case TYPE_NOT_CONTAINS:
00197 m_comparison_func = boost::shared_ptr<ComparisonFunctor>(new CompareStringContains(m_str_value));
00198 break;
00199 case TYPE_CONTAINS_PRIMARY:
00200 case TYPE_NOT_CONTAINS_PRIMARY:
00201 m_comparison_func = boost::shared_ptr<ComparisonFunctor>(new CompareStringContains(m_str_value, UCOL_PRIMARY));
00202 break;
00203 case TYPE_STARTS_WITH:
00204 case TYPE_NOT_STARTS_WITH:
00205 m_comparison_func = boost::shared_ptr<ComparisonFunctor>(new CompareStringStartsWith(m_str_value));
00206 break;
00207 case TYPE_STARTS_WITH_PRIMARY:
00208 case TYPE_NOT_STARTS_WITH_PRIMARY:
00209 m_comparison_func = boost::shared_ptr<ComparisonFunctor>(new CompareStringStartsWith(m_str_value, UCOL_PRIMARY));
00210 break;
00211 case TYPE_ENDS_WITH:
00212 case TYPE_NOT_ENDS_WITH:
00213 m_comparison_func = boost::shared_ptr<ComparisonFunctor>(new CompareStringEndsWith(m_str_value));
00214 break;
00215 case TYPE_ENDS_WITH_PRIMARY:
00216 case TYPE_NOT_ENDS_WITH_PRIMARY:
00217 m_comparison_func = boost::shared_ptr<ComparisonFunctor>(new CompareStringEndsWith(m_str_value, UCOL_PRIMARY));
00218 break;
00219 case TYPE_ORDERED_BEFORE:
00220 case TYPE_NOT_ORDERED_BEFORE:
00221 m_comparison_func = boost::shared_ptr<ComparisonFunctor>(new CompareStringOrderedBefore(m_str_value));
00222 break;
00223 case TYPE_ORDERED_BEFORE_PRIMARY:
00224 case TYPE_NOT_ORDERED_BEFORE_PRIMARY:
00225 m_comparison_func = boost::shared_ptr<ComparisonFunctor>(new CompareStringOrderedBefore(m_str_value, UCOL_PRIMARY));
00226 break;
00227 case TYPE_ORDERED_AFTER:
00228 case TYPE_NOT_ORDERED_AFTER:
00229 m_comparison_func = boost::shared_ptr<ComparisonFunctor>(new CompareStringOrderedAfter(m_str_value));
00230 break;
00231 case TYPE_ORDERED_AFTER_PRIMARY:
00232 case TYPE_NOT_ORDERED_AFTER_PRIMARY:
00233 m_comparison_func = boost::shared_ptr<ComparisonFunctor>(new CompareStringOrderedAfter(m_str_value, UCOL_PRIMARY));
00234 break;
00235 case TYPE_FALSE:
00236 case TYPE_TRUE:
00237 case TYPE_IS_DEFINED:
00238 case TYPE_IS_NOT_DEFINED:
00239 case TYPE_REGEX:
00240 case TYPE_NOT_REGEX:
00241
00242 break;
00243 case TYPE_EQUALS:
00244 case TYPE_NOT_EQUALS:
00245 case TYPE_GREATER_THAN:
00246 case TYPE_LESS_THAN:
00247 case TYPE_GREATER_OR_EQUAL:
00248 case TYPE_LESS_OR_EQUAL:
00249 case TYPE_SAME_DATE_TIME:
00250 case TYPE_NOT_SAME_DATE_TIME:
00251 case TYPE_EARLIER_DATE_TIME:
00252 case TYPE_LATER_DATE_TIME:
00253 case TYPE_SAME_OR_EARLIER_DATE_TIME:
00254 case TYPE_SAME_OR_LATER_DATE_TIME:
00255 case TYPE_SAME_DATE:
00256 case TYPE_NOT_SAME_DATE:
00257 case TYPE_EARLIER_DATE:
00258 case TYPE_LATER_DATE:
00259 case TYPE_SAME_OR_EARLIER_DATE:
00260 case TYPE_SAME_OR_LATER_DATE:
00261 case TYPE_SAME_TIME:
00262 case TYPE_NOT_SAME_TIME:
00263 case TYPE_EARLIER_TIME:
00264 case TYPE_LATER_TIME:
00265 case TYPE_SAME_OR_EARLIER_TIME:
00266 case TYPE_SAME_OR_LATER_TIME:
00267
00268 throw InvalidComparisonException();
00269 }
00270 } else if (requiresValue(type)) {
00271 try {
00272
00273 switch(m_term.term_type) {
00274 case Vocabulary::TYPE_NULL:
00275 case Vocabulary::TYPE_OBJECT:
00276 break;
00277 case Vocabulary::TYPE_INT8:
00278 case Vocabulary::TYPE_INT16:
00279 case Vocabulary::TYPE_INT32:
00280 m_value = boost::lexical_cast<boost::int32_t>(value);
00281 break;
00282 case Vocabulary::TYPE_INT64:
00283 m_value = boost::lexical_cast<boost::int64_t>(value);
00284 break;
00285 case Vocabulary::TYPE_UINT8:
00286 case Vocabulary::TYPE_UINT16:
00287 case Vocabulary::TYPE_UINT32:
00288 m_value = boost::lexical_cast<boost::uint32_t>(value);
00289 break;
00290 case Vocabulary::TYPE_UINT64:
00291 m_value = boost::lexical_cast<boost::uint64_t>(value);
00292 break;
00293 case Vocabulary::TYPE_FLOAT:
00294 m_value = boost::lexical_cast<float>(value);
00295 break;
00296 case Vocabulary::TYPE_DOUBLE:
00297 m_value = boost::lexical_cast<double>(value);
00298 break;
00299 case Vocabulary::TYPE_LONG_DOUBLE:
00300 m_value = boost::lexical_cast<long double>(value);
00301 break;
00302 case Vocabulary::TYPE_SHORT_STRING:
00303 case Vocabulary::TYPE_STRING:
00304 case Vocabulary::TYPE_LONG_STRING:
00305 case Vocabulary::TYPE_CHAR:
00306 case Vocabulary::TYPE_BLOB:
00307 case Vocabulary::TYPE_ZBLOB:
00308 m_str_value = value;
00309 break;
00310 case Vocabulary::TYPE_DATE_TIME:
00311 case Vocabulary::TYPE_DATE:
00312 case Vocabulary::TYPE_TIME:
00313
00314 PionTimeFacet f(m_term.term_format);
00315 m_value = f.fromString(value);
00316 break;
00317 }
00318 } catch (...) {
00319 throw InvalidValueForTypeException();
00320 }
00321 }
00322
00323 m_type = type;
00324 m_match_all_values = match_all_values;
00325 }
00326
00327 void Comparison::configure(const ComparisonType type)
00328 {
00329 if (! checkForValidType(type))
00330 throw InvalidTypeForTermException();
00331 if (requiresValue(type))
00332 throw InvalidValueForTypeException();
00333
00334 m_type = type;
00335 m_value = Event::ParameterValue();
00336 m_match_all_values = false;
00337 }
00338
00339 void Comparison::updateVocabulary(const Vocabulary& v)
00340 {
00341 v.refreshTerm(m_term);
00342 }
00343
00344 Comparison::ComparisonType Comparison::parseComparisonType(std::string str)
00345 {
00346
00347 for (std::string::iterator i=str.begin(); i!=str.end(); ++i)
00348 if (isupper(*i)) *i = tolower(*i);
00349
00350
00351 for (size_t j = 0; j < sizeof(comparison_table) / sizeof(comparison_table[0]); ++j)
00352 if (str == comparison_table[j].name)
00353 return comparison_table[j].type;
00354
00355 throw UnknownComparisonTypeException(str);
00356 }
00357
00358 std::string Comparison::getComparisonTypeAsString(const ComparisonType comparison_type)
00359 {
00360 return comparison_table[comparison_type].name;
00361 }
00362
00363 bool Comparison::requiresValue(ComparisonType t) {
00364 return comparison_table[t].arity > 1;
00365 }
00366
00367 void Comparison::writeComparisonsXML(std::ostream& out) {
00368 for (size_t i = 0; i < sizeof(comparison_table) / sizeof(comparison_table[0]); ++i) {
00369 out << "<Comparison id=\"" << comparison_table[i].name << "\"><Arity>"
00370 << (unsigned)comparison_table[i].arity << "</Arity>";
00371 if (comparison_table[i].is_generic)
00372 out << "<Category>generic</Category>";
00373 if (comparison_table[i].applies_to_numeric_terms)
00374 out << "<Category>numeric</Category>";
00375 if (comparison_table[i].applies_to_string_terms)
00376 out << "<Category>string</Category>";
00377 if (comparison_table[i].applies_to_date_time_terms)
00378 out << "<Category>date_time</Category>";
00379 if (comparison_table[i].applies_to_date_terms)
00380 out << "<Category>date</Category>";
00381 if (comparison_table[i].applies_to_time_terms)
00382 out << "<Category>time</Category>";
00383 out << "</Comparison>" << std::endl;
00384 }
00385 }
00386
00387 Comparison::ComparisonFunctor::ComparisonFunctor(const std::string& value, UColAttributeValue attr) : m_pattern_buf(NULL) {
00388 UErrorCode errorCode = U_ZERO_ERROR;
00389 m_collator = ucol_open(NULL, &errorCode);
00390
00393
00394 if (attr != UCOL_DEFAULT)
00395 ucol_setAttribute(m_collator, UCOL_STRENGTH, attr, &errorCode);
00396
00397
00398 u_strFromUTF8(NULL, 0, &m_pattern_buf_len, value.c_str(), -1, &errorCode);
00399 errorCode = U_ZERO_ERROR;
00400 m_pattern_buf = new UChar[m_pattern_buf_len];
00401 u_strFromUTF8(m_pattern_buf, m_pattern_buf_len, NULL, value.c_str(), -1, &errorCode);
00402 }
00403
00404 Comparison::ComparisonFunctor::~ComparisonFunctor() {
00405 delete [] m_pattern_buf;
00406 ucol_close(m_collator);
00407 }
00408
00409 Comparison::CompareStringExactMatch::CompareStringExactMatch(const std::string& value, UColAttributeValue attr) : ComparisonFunctor(value, attr) {
00410 }
00411
00412 Comparison::CompareStringContains::CompareStringContains(const std::string& value, UColAttributeValue attr) : ComparisonFunctor(value, attr) {
00413 }
00414
00415 Comparison::CompareStringStartsWith::CompareStringStartsWith(const std::string& value, UColAttributeValue attr) : ComparisonFunctor(value, attr) {
00416 }
00417
00418 Comparison::CompareStringStartsWith::~CompareStringStartsWith() {
00419 }
00420
00421 Comparison::CompareStringEndsWith::CompareStringEndsWith(const std::string& value, UColAttributeValue attr) : ComparisonFunctor(value, attr) {
00422 }
00423
00424 Comparison::CompareStringOrderedBefore::CompareStringOrderedBefore(const std::string& value, UColAttributeValue attr) : ComparisonFunctor(value, attr) {
00425 }
00426
00427 Comparison::CompareStringOrderedAfter::CompareStringOrderedAfter(const std::string& value, UColAttributeValue attr) : ComparisonFunctor(value, attr) {
00428 }
00429
00430
00431 }
00432 }