platform/src/Comparison.cpp

00001 // ------------------------------------------------------------------------
00002 // Pion is a development platform for building Reactors that process Events
00003 // ------------------------------------------------------------------------
00004 // Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
00005 //
00006 // Pion is free software: you can redistribute it and/or modify it under the
00007 // terms of the GNU Affero General Public License as published by the Free
00008 // Software Foundation, either version 3 of the License, or (at your option)
00009 // any later version.
00010 //
00011 // Pion is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
00014 // more details.
00015 //
00016 // You should have received a copy of the GNU Affero General Public License
00017 // along with Pion.  If not, see <http://www.gnu.org/licenses/>.
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 {        // begin namespace pion
00029 namespace platform {    // begin namespace platform (Pion Platform Library)
00030 
00031 
00032 struct comparison_info {
00033     Comparison::ComparisonType  type;       // must equal the index, i.e. comparison_table[i].type == i
00034     const char*                 name;       // Comparison term in UI
00035     boost::uint8_t              arity;      // how many arguments
00036     bool                        is_generic;                 // is the comparison applicable to any type of Term
00037     bool                        applies_to_numeric_terms;   // is the comparison applicable to Terms of category numeric
00038     bool                        applies_to_string_terms;    // is the comparison applicable to Terms of category string
00039     bool                        applies_to_date_time_terms; // is the comparison applicable to Terms of category date_time
00040     bool                        applies_to_date_terms;      // is the comparison applicable to Terms of category date
00041     bool                        applies_to_time_terms;      // is the comparison applicable to Terms of category time
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 // Comparison member functions
00111 
00112 bool Comparison::checkForValidType(const ComparisonType type) const
00113 {
00114     bool result = false;
00115     
00116     if (comparison_table[type].is_generic) {
00117         // generic comparisons are always valid
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         // Test value to make sure it's a valid UTF-8 string.
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) // U_BUFFER_OVERFLOW_ERROR is expected since destCapacity = 0
00175             throw InvalidComparisonException();
00176 
00177         // TODO: Make more specific exceptions, e.g. InvalidCharInUtf8StringException & Utf8StringException.
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                 // these do not use m_comparison_func
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                 // these do not apply to string terms -> should never happen
00268                 throw InvalidComparisonException();
00269         }
00270     } else if (requiresValue(type)) {       // note: comparisons of arity 1 just ignore the value
00271         try {
00272             // convert string to be the same type as the term
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;    // this should actually be handled above
00309                     break;
00310                 case Vocabulary::TYPE_DATE_TIME:
00311                 case Vocabulary::TYPE_DATE:
00312                 case Vocabulary::TYPE_TIME:
00313                     //m_value = boost::lexical_cast<PionDateTime>(value);
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     // convert to lowercase
00347     for (std::string::iterator i=str.begin(); i!=str.end(); ++i)
00348         if (isupper(*i)) *i = tolower(*i);
00349 
00350     // Search for a matching entry in comparison_table and return the corresponding type.
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     // TODO: check errorCode.
00393 
00394     if (attr != UCOL_DEFAULT)
00395         ucol_setAttribute(m_collator, UCOL_STRENGTH, attr, &errorCode);
00396         // TODO: check errorCode.
00397 
00398     u_strFromUTF8(NULL, 0, &m_pattern_buf_len, value.c_str(), -1, &errorCode);
00399     errorCode = U_ZERO_ERROR; // Need to reset, because u_strFromUTF8 returns U_BUFFER_OVERFLOW_ERROR when destCapacity = 0.
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 }   // end namespace platform
00432 }   // end namespace pion

Generated on Wed Apr 13 16:38:34 2011 for pion-platform by  doxygen 1.4.7