From ae91a7cf4f325749bb46c2fb2df1d141d710b17f Mon Sep 17 00:00:00 2001 From: Ramin Yaghoubzadeh <ryaghoubzadeh@uni-bielefeld.de> Date: Thu, 26 Feb 2015 17:57:06 +0100 Subject: [PATCH] C++: stricter type conversions (to be discussed) PayloadTypeConversionError thrown if (trimmed) string parse is incomplete; comparison operators == and != catch this error though. --- .../cpp/include/ipaaca/ipaaca-definitions.h | 9 ++++ ipaacalib/cpp/include/ipaaca/ipaaca-payload.h | 22 ++++++++ ipaacalib/cpp/src/ipaaca-json.cc | 16 ++++++ ipaacalib/cpp/src/ipaaca-payload.cc | 51 ++++++++++++++----- ipaacalib/cpp/src/ipaaca-string-utils.cc | 12 +++++ 5 files changed, 97 insertions(+), 13 deletions(-) diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h b/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h index 681837b..ffdb05c 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h @@ -210,6 +210,14 @@ IPAACA_HEADER_EXPORT class NotImplementedError: public Exception//{{{ _description = "NotImplementedError"; } };//}}} +IPAACA_HEADER_EXPORT class PayloadTypeConversionError: public Exception//{{{ +{ + public: + IPAACA_HEADER_EXPORT inline ~PayloadTypeConversionError() throw() { } + IPAACA_HEADER_EXPORT inline PayloadTypeConversionError() { //boost::shared_ptr<IU> iu) { + _description = "PayloadTypeConversionError"; + } +};//}}} IPAACA_HEADER_EXPORT class PayloadAddressingError: public Exception//{{{ { public: @@ -308,6 +316,7 @@ class CommandLineParser { //}}} // in ipaaca-string-utils.cc // additional misc functions ( String splitting / joining )//{{{ +IPAACA_HEADER_EXPORT std::string str_trim(const std::string &s); IPAACA_HEADER_EXPORT std::string str_join(const std::set<std::string>& set,const std::string& sep); IPAACA_HEADER_EXPORT std::string str_join(const std::vector<std::string>& vec,const std::string& sep); IPAACA_HEADER_EXPORT void str_split_wipe(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters ); diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h index becd6dc..a4d2f26 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h @@ -44,6 +44,7 @@ IPAACA_HEADER_EXPORT template<typename T> T json_value_cast(const rapidjson::Value&); IPAACA_HEADER_EXPORT template<typename T> T json_value_cast(const rapidjson::Value* value) { if (!value) return T(); return json_value_cast<T>(*value); } IPAACA_HEADER_EXPORT template<> long json_value_cast(const rapidjson::Value&); +IPAACA_HEADER_EXPORT template<> int json_value_cast(const rapidjson::Value&); IPAACA_HEADER_EXPORT template<> double json_value_cast(const rapidjson::Value&); IPAACA_HEADER_EXPORT template<> bool json_value_cast(const rapidjson::Value&); IPAACA_HEADER_EXPORT template<> std::string json_value_cast(const rapidjson::Value&); @@ -53,6 +54,7 @@ IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> json_value_ca // helpers to set Value& from various standard types //IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, T t); +IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, int); IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, long); IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, double); IPAACA_HEADER_EXPORT void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, bool); @@ -301,6 +303,26 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ _payload->set(_key, new_entry); return *this; } + IPAACA_HEADER_EXPORT inline bool operator==(const PayloadEntryProxy& otherproxy) { return (json_value && otherproxy.json_value && ((*json_value)==*(otherproxy.json_value))); } + IPAACA_HEADER_EXPORT inline bool operator!=(const PayloadEntryProxy& otherproxy) { return !operator==(otherproxy); } + IPAACA_HEADER_EXPORT template<typename T> bool operator==(T othervalue) + { + if (!json_value) return false; + try { + return json_value_cast<T>(*json_value) == othervalue; + } catch(PayloadTypeConversionError& ex) { + // assume conversion error = type mismatch = unequal + return false; + } + } + IPAACA_HEADER_EXPORT template<typename T> bool operator!=(T othervalue) { return !operator==(othervalue); } + IPAACA_HEADER_EXPORT inline bool operator==(const char* othervalue) + { + if (!json_value) return false; + return json_value_cast<std::string>(*json_value) == othervalue; + } + IPAACA_HEADER_EXPORT inline bool operator!=(const char* othervalue) { return !operator==(othervalue); } + IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const PayloadEntryProxy& otherproxy); //IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const std::string& value); diff --git a/ipaacalib/cpp/src/ipaaca-json.cc b/ipaacalib/cpp/src/ipaaca-json.cc index 943f89e..3be11f6 100644 --- a/ipaacalib/cpp/src/ipaaca-json.cc +++ b/ipaacalib/cpp/src/ipaaca-json.cc @@ -47,13 +47,29 @@ int iterators_main(int argc, char** argv)//{{{ ipaaca::FakeIU::ptr iu = ipaaca::FakeIU::create(); iu->add_fake_payload_item("a", entry); iu->payload()["b"] = "simpleString"; + iu->payload()["bPrime"] = "simpleString"; iu->payload()["c"] = "anotherSimpleString"; + iu->payload()["d"] = 100; + iu->payload()["e"] = 10000l; std::cout << "Iterate over payload" << std::endl; for (auto it = iu->payload().begin(); it != iu->payload().end(); ++it) { std::cout << " " << it->first << " -> " << it->second << std::endl; } + std::cout << "Comparisons" << std::endl; + bool eq; + eq = iu->payload()["a"] == iu->payload()["b"]; + std::cout << " a==b ? : " << (eq?"true":"false") << std::endl; + eq = iu->payload()["b"] == iu->payload()["bPrime"]; + std::cout << " b==bPrime ? : " << (eq?"true":"false") << std::endl; + eq = iu->payload()["b"] == "simpleString"; + std::cout << " b==\"simpleString\" ? : " << (eq?"true":"false") << std::endl; + eq = iu->payload()["b"] == 100; + std::cout << " b==100 ? : " << (eq?"true":"false") << std::endl; + eq = iu->payload()["d"] == 100; + std::cout << " d==100 ? : " << (eq?"true":"false") << std::endl; + return 0; } //}}} diff --git a/ipaacalib/cpp/src/ipaaca-payload.cc b/ipaacalib/cpp/src/ipaaca-payload.cc index 5989272..e8c6d14 100644 --- a/ipaacalib/cpp/src/ipaaca-payload.cc +++ b/ipaacalib/cpp/src/ipaaca-payload.cc @@ -90,6 +90,20 @@ IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const Payload& obj)//{{ } //}}} +double strict_numerical_interpretation(const std::string& str) +{ + char* endptr; + auto s = str_trim(str); + const char* startptr = s.c_str(); + long l = strtod(startptr, &endptr); + if ((*endptr)=='\0') { + // everything could be parsed + return l; + } else { + throw PayloadTypeConversionError(); + } +} + // json_value_cast//{{{ IPAACA_EXPORT template<> std::string json_value_cast(const rapidjson::Value& v) { @@ -102,7 +116,7 @@ IPAACA_EXPORT template<> std::string json_value_cast(const rapidjson::Value& v) } IPAACA_EXPORT template<> long json_value_cast(const rapidjson::Value& v) { - if (v.IsString()) return atol(std::string(v.GetString()).c_str()); + if (v.IsString()) return (long) strict_numerical_interpretation(v.GetString()); if (v.IsInt()) return v.GetInt(); if (v.IsUint()) return v.GetUint(); if (v.IsInt64()) return v.GetInt64(); @@ -111,14 +125,29 @@ IPAACA_EXPORT template<> long json_value_cast(const rapidjson::Value& v) if (v.IsBool()) return v.GetBool() ? 1l : 0l; if (v.IsNull()) return 0l; // default: return parse of string version (should always be 0 though?) + throw PayloadTypeConversionError(); + /* rapidjson::StringBuffer buffer; rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); v.Accept(writer); return atol(std::string(buffer.GetString()).c_str()); + */ +} +IPAACA_EXPORT template<> int json_value_cast(const rapidjson::Value& v) +{ + if (v.IsString()) return (int) strict_numerical_interpretation(v.GetString()); + if (v.IsInt()) return v.GetInt(); + if (v.IsUint()) return v.GetUint(); + if (v.IsInt64()) return v.GetInt64(); + if (v.IsUint64()) return v.GetUint64(); + if (v.IsDouble()) return (long) v.GetDouble(); + if (v.IsBool()) return v.GetBool() ? 1l : 0l; + if (v.IsNull()) return 0l; + throw PayloadTypeConversionError(); } IPAACA_EXPORT template<> double json_value_cast(const rapidjson::Value& v) { - if (v.IsString()) return atof(std::string(v.GetString()).c_str()); + if (v.IsString()) return strict_numerical_interpretation(v.GetString()); if (v.IsDouble()) return v.GetDouble(); if (v.IsInt()) return (double) v.GetInt(); if (v.IsUint()) return (double) v.GetUint(); @@ -126,11 +155,7 @@ IPAACA_EXPORT template<> double json_value_cast(const rapidjson::Value& v) if (v.IsUint64()) return (double) v.GetUint64(); if (v.IsBool()) return v.GetBool() ? 1.0 : 0.0; if (v.IsNull()) return 0.0; - // default: return parse of string version (should always be 0.0 though?) - rapidjson::StringBuffer buffer; - rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); - v.Accept(writer); - return atof(std::string(buffer.GetString()).c_str()); + throw PayloadTypeConversionError(); } IPAACA_EXPORT template<> bool json_value_cast(const rapidjson::Value& v) { @@ -146,12 +171,8 @@ IPAACA_EXPORT template<> bool json_value_cast(const rapidjson::Value& v) if (v.IsInt64()) return v.GetInt64() != 0; if (v.IsUint64()) return v.GetUint64() != 0; if (v.IsDouble()) return v.GetDouble() != 0.0; - // default: return parse of string version (should always be 0.0 though?) - rapidjson::StringBuffer buffer; - rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); - v.Accept(writer); - std::string s = buffer.GetString(); - return !((s=="")||(s=="false")||(s=="False")||(s=="0")); + // default: assume "pointer-like" semantics (i.e. objects are TRUE) + return true; } /* * std::map<std::string, std::string> result; @@ -161,6 +182,10 @@ IPAACA_EXPORT template<> bool json_value_cast(const rapidjson::Value& v) */ //}}} +IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, int newvalue) +{ + valueobject.SetInt(newvalue); +} IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, long newvalue) { valueobject.SetInt(newvalue); diff --git a/ipaacalib/cpp/src/ipaaca-string-utils.cc b/ipaacalib/cpp/src/ipaaca-string-utils.cc index 992d7cd..d3192fc 100644 --- a/ipaacalib/cpp/src/ipaaca-string-utils.cc +++ b/ipaacalib/cpp/src/ipaaca-string-utils.cc @@ -32,8 +32,20 @@ #include <ipaaca/ipaaca.h> +#include <cctype> +#include <string> +#include <algorithm> + + namespace ipaaca { +std::string str_trim(const std::string &s) +{ + auto wsfront = std::find_if_not(s.begin(), s.end(), [](int c){ return std::isspace(c); } ); + auto wsback = std::find_if_not(s.rbegin(), s.rend(), [](int c){ return std::isspace(c); } ).base(); + return (wsback<=wsfront ? std::string() : std::string(wsfront, wsback)); +} + std::string str_join(const std::set<std::string>& set,const std::string& sep) { if(set.size()==0) -- GitLab