diff --git a/Foundation/Foundation_vs71.vcproj b/Foundation/Foundation_vs71.vcproj index d9a60f2be..074183f8e 100644 --- a/Foundation/Foundation_vs71.vcproj +++ b/Foundation/Foundation_vs71.vcproj @@ -3653,6 +3653,11 @@ RelativePath=".\include\Poco\DynamicStruct.h" > + + + diff --git a/Foundation/Foundation_vs80.vcproj b/Foundation/Foundation_vs80.vcproj index 9d23d90f2..414e179aa 100644 --- a/Foundation/Foundation_vs80.vcproj +++ b/Foundation/Foundation_vs80.vcproj @@ -4741,6 +4741,10 @@ RelativePath=".\include\Poco\DynamicStruct.h" > + + diff --git a/Foundation/Foundation_vs90.vcproj b/Foundation/Foundation_vs90.vcproj index db8336d78..6e440da21 100644 --- a/Foundation/Foundation_vs90.vcproj +++ b/Foundation/Foundation_vs90.vcproj @@ -4732,6 +4732,10 @@ RelativePath=".\include\Poco\DynamicStruct.h" > + + diff --git a/Foundation/include/Poco/Dynamic/Pair.h b/Foundation/include/Poco/Dynamic/Pair.h new file mode 100644 index 000000000..b3fa54688 --- /dev/null +++ b/Foundation/include/Poco/Dynamic/Pair.h @@ -0,0 +1,427 @@ +// +// Pair.h +// +// $Id: //poco/Main/Foundation/include/Poco/Dynamic/Pair.h#9 $ +// +// Library: Foundation +// Package: Dynamic +// Module: Pair +// +// Definition of the Pair class. +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Foundation_Pair_INCLUDED +#define Foundation_Pair_INCLUDED + + +#include "Poco/Foundation.h" +#include "Poco/Dynamic/Var.h" +#include "Poco/Dynamic/VarHolder.h" +#include + + +namespace Poco { +namespace Dynamic { + + +template +class Pair + /// Pair allows to define a pair of values. +{ +public: + typedef typename std::pair Data; + + Pair(): _data() + /// Creates an empty Pair + { + } + + Pair(const Pair& other): _data(other._data) + /// Creates the Pair from another pair. + { + } + + Pair(const Data& val): _data(val) + /// Creates the Pair from the given value. + { + } + + template + Pair(const std::pair& val): _data(std::make_pair(val.first, Var(val.second))) + /// Creates Pair form standard pair. + { + } + + template + Pair(const K& first, const T& second): _data(std::make_pair(first, Var(second))) + /// Creates pair from two values. + { + } + + virtual ~Pair() + /// Destroys the Pair. + { + } + + Pair& swap(Pair& other) + /// Swaps the content of the two Pairs. + { + std::swap(_data, other._data); + return *this; + } + + Pair& operator = (const Pair& other) + /// Copy constructs Pair from another pair. + { + Pair(other).swap(*this); + return *this; + } + + inline const K& first() const + /// Returns the first member of the pair. + { + return _data.first; + } + + inline const Var& second() const + /// Returns the second member of the pair. + { + return _data.second; + } + +private: + Data _data; +}; + + +template <> +class VarHolderImpl >: public VarHolder +{ +public: + VarHolderImpl(const Pair& val): _val(val) + { + } + + ~VarHolderImpl() + { + } + + const std::type_info& type() const + { + return typeid(Pair); + } + + void convert(Int8& val) const + { + throw BadCastException("Cannot cast Pair type to Int8"); + } + + void convert(Int16& val) const + { + throw BadCastException("Cannot cast Pair type to Int16"); + } + + void convert(Int32& val) const + { + throw BadCastException("Cannot cast Pair type to Int32"); + } + + void convert(Int64& val) const + { + throw BadCastException("Cannot cast Pair type to Int64"); + } + + void convert(UInt8& val) const + { + throw BadCastException("Cannot cast Pair type to UInt8"); + } + + void convert(UInt16& val) const + { + throw BadCastException("Cannot cast Pair type to UInt16"); + } + + void convert(UInt32& val) const + { + throw BadCastException("Cannot cast Pair type to UInt32"); + } + + void convert(UInt64& val) const + { + throw BadCastException("Cannot cast Pair type to UInt64"); + } + + void convert(bool& val) const + { + throw BadCastException("Cannot cast Pair type to bool"); + } + + void convert(float& val) const + { + throw BadCastException("Cannot cast Pair type to float"); + } + + void convert(double& val) const + { + throw BadCastException("Cannot cast Pair type to double"); + } + + void convert(char& val) const + { + throw BadCastException("Cannot cast Pair type to char"); + } + + void convert(std::string& val) const + { + // Serialize in JSON format: equals an object + // JSON format definition: { string ':' value } string:value pair n-times, sep. by ',' + val.append("{ "); + Var key(_val.first()); + appendJSONString(val, key); + val.append(" : "); + appendJSONString(val, _val.second()); + val.append(" }"); + } + + void convert(Poco::DateTime&) const + { + throw BadCastException("Pair -> Poco::DateTime"); + } + + void convert(Poco::LocalDateTime&) const + { + throw BadCastException("Pair -> Poco::LocalDateTime"); + } + + void convert(Poco::Timestamp&) const + { + throw BadCastException("Pair -> Poco::Timestamp"); + } + + VarHolder* clone() const + { + return new VarHolderImpl(_val); + } + + const Pair& value() const + { + return _val; + } + + bool isArray() const + { + return false; + } + + bool isStruct() const + { + return false; + } + + bool isInteger() const + { + return false; + } + + bool isSigned() const + { + return false; + } + + bool isNumeric() const + { + return false; + } + + bool isString() const + { + return false; + } + +private: + Pair _val; +}; + + +template <> +class VarHolderImpl >: public VarHolder +{ +public: + VarHolderImpl(const Pair& val): _val(val) + { + } + + ~VarHolderImpl() + { + } + + const std::type_info& type() const + { + return typeid(Pair); + } + + void convert(Int8& val) const + { + throw BadCastException("Cannot cast Pair type to Int8"); + } + + void convert(Int16& val) const + { + throw BadCastException("Cannot cast Pair type to Int16"); + } + + void convert(Int32& val) const + { + throw BadCastException("Cannot cast Pair type to Int32"); + } + + void convert(Int64& val) const + { + throw BadCastException("Cannot cast Pair type to Int64"); + } + + void convert(UInt8& val) const + { + throw BadCastException("Cannot cast Pair type to UInt8"); + } + + void convert(UInt16& val) const + { + throw BadCastException("Cannot cast Pair type to UInt16"); + } + + void convert(UInt32& val) const + { + throw BadCastException("Cannot cast Pair type to UInt32"); + } + + void convert(UInt64& val) const + { + throw BadCastException("Cannot cast Pair type to UInt64"); + } + + void convert(bool& val) const + { + throw BadCastException("Cannot cast Pair type to bool"); + } + + void convert(float& val) const + { + throw BadCastException("Cannot cast Pair type to float"); + } + + void convert(double& val) const + { + throw BadCastException("Cannot cast Pair type to double"); + } + + void convert(char& val) const + { + throw BadCastException("Cannot cast Pair type to char"); + } + + void convert(std::string& val) const + { + // Serialize in JSON format: equals an object + // JSON format definition: { string ':' value } string:value pair n-times, sep. by ',' + val.append("{ "); + Var key(_val.first()); + appendJSONString(val, key); + val.append(" : "); + appendJSONString(val, _val.second()); + val.append(" }"); + } + + void convert(Poco::DateTime&) const + { + throw BadCastException("Pair -> Poco::DateTime"); + } + + void convert(Poco::LocalDateTime&) const + { + throw BadCastException("Pair -> Poco::LocalDateTime"); + } + + void convert(Poco::Timestamp&) const + { + throw BadCastException("Pair -> Poco::Timestamp"); + } + + VarHolder* clone() const + { + return new VarHolderImpl(_val); + } + + const Pair& value() const + { + return _val; + } + + bool isArray() const + { + return false; + } + + bool isStruct() const + { + return false; + } + + bool isInteger() const + { + return false; + } + + bool isSigned() const + { + return false; + } + + bool isNumeric() const + { + return false; + } + + bool isString() const + { + return false; + } + +private: + Pair _val; +}; + + +} // namespace Dynamic + + +} // namespace Poco + + +#endif // Foundation_Pair_INCLUDED diff --git a/Foundation/include/Poco/Dynamic/Struct.h b/Foundation/include/Poco/Dynamic/Struct.h index 27a828b43..5a315c6e7 100644 --- a/Foundation/include/Poco/Dynamic/Struct.h +++ b/Foundation/include/Poco/Dynamic/Struct.h @@ -1,7 +1,7 @@ // // Struct.h // -// $Id: //poco/Main/Foundation/include/Poco/Struct.h#9 $ +// $Id: //poco/Main/Foundation/include/Poco/Dynamic/Struct.h#9 $ // // Library: Foundation // Package: Dynamic @@ -69,7 +69,7 @@ public: { } - Struct(const Data &val): _data(val) + Struct(const Data& val): _data(val) /// Creates the Struct from the given value. { } @@ -286,9 +286,6 @@ public: void convert(std::string& val) const { - // Serialize in JSON format: equals an object - - // JSON format definition: { string ':' value } string:value pair n-times, sep. by ',' val.append("{ "); Struct::ConstIterator it = _val.begin(); Struct::ConstIterator itEnd = _val.end(); @@ -460,9 +457,6 @@ public: void convert(std::string& val) const { - // Serialize in JSON format: equals an object - - // JSON format definition: { string ':' value } string:value pair n-times, sep. by ',' val.append("{ "); Struct::ConstIterator it = _val.begin(); Struct::ConstIterator itEnd = _val.end(); diff --git a/Foundation/include/Poco/Dynamic/Var.h b/Foundation/include/Poco/Dynamic/Var.h index 078cb74e7..56b32e2c6 100644 --- a/Foundation/include/Poco/Dynamic/Var.h +++ b/Foundation/include/Poco/Dynamic/Var.h @@ -53,7 +53,6 @@ namespace Dynamic { template class Struct; - class Foundation_API Var /// Var allows to store data of different types and to convert between these types transparently. /// Var puts forth the best effort to provide intuitive and reasonable conversion semantics and prevent diff --git a/Foundation/include/Poco/Dynamic/VarHolder.h b/Foundation/include/Poco/Dynamic/VarHolder.h index a0dfa74f7..12465f9f4 100644 --- a/Foundation/include/Poco/Dynamic/VarHolder.h +++ b/Foundation/include/Poco/Dynamic/VarHolder.h @@ -65,6 +65,9 @@ namespace Dynamic { class Var; +bool Foundation_API isJSONString(const Var& any); + /// Returns true for values that should be JSON-formatted as string. + void Foundation_API appendJSONString(std::string& val, const Var& any); /// Converts the any to a JSON value and adds it to val diff --git a/Foundation/src/Var.cpp b/Foundation/src/Var.cpp index 84e19076d..e9457946d 100644 --- a/Foundation/src/Var.cpp +++ b/Foundation/src/Var.cpp @@ -423,12 +423,12 @@ Var Var::parseArray(const std::string& val, std::string::size_type& pos) std::string Var::parseString(const std::string& val, std::string::size_type& pos) { - static const std::string STR_STOP("'\""); + static const std::string STR_STOP("\""); static const std::string OTHER_STOP(" ,]}"); // we stop at space, ',', ']' or '}' bool inString = false; //skip optional ' " - if (val[pos] == '\'' || val[pos] == '"') + if (val[pos] == '"') { inString = true; ++pos; diff --git a/Foundation/src/VarHolder.cpp b/Foundation/src/VarHolder.cpp index 6473b37d6..702082417 100644 --- a/Foundation/src/VarHolder.cpp +++ b/Foundation/src/VarHolder.cpp @@ -52,17 +52,24 @@ VarHolder::~VarHolder() } +bool isJSONString(const Var& any) +{ + return any.type() == typeid(std::string) || + any.type() == typeid(char) || + any.type() == typeid(Poco::DateTime) || + any.type() == typeid(Poco::LocalDateTime); +} + + void appendJSONString(std::string& val, const Var& any) { - bool isJsonString = (any.type() == typeid(std::string) || any.type() == typeid(char) || any.type() == typeid(Poco::DateTime) || any.type() == typeid(Poco::LocalDateTime)); - if (isJsonString) + if (any.isEmpty()) val.append("null"); + else { - val.append(1, '\''); - } - val.append(any.convert()); - if (isJsonString) - { - val.append(1, '\''); + bool isStr = isJSONString(any); + if (isStr) val.append(1, '"'); + val.append(any.convert()); + if (isStr) val.append(1, '"'); } } diff --git a/Foundation/testsuite/src/VarTest.cpp b/Foundation/testsuite/src/VarTest.cpp index 7d36a2fdc..75a99a2d7 100644 --- a/Foundation/testsuite/src/VarTest.cpp +++ b/Foundation/testsuite/src/VarTest.cpp @@ -36,11 +36,13 @@ #include "Poco/Exception.h" #include "Poco/Dynamic/Var.h" #include "Poco/Bugcheck.h" -#include "Poco/DynamicStruct.h" +#include "Poco/Dynamic/Struct.h" +#include "Poco/Dynamic/Pair.h" +#include +#include - -#if defined(_MSC_VER) && _MSC_VER < 1400 - #pragma warning(disable:4800)//forcing value to bool 'true' or 'false' +#if defined(_MSC_VER) && _MSC_VER < 1400 + #pragma warning(disable:4800)//forcing value to bool 'true' or 'false' #endif @@ -2010,6 +2012,49 @@ void VarTest::testDynamicStructInt() } +void VarTest::testDynamicPair() +{ + Pair aPair; + assert (0 == aPair.first()); + try + { + std::string s = aPair.second().convert(); + fail ("must fail"); + } + catch (InvalidAccessException&) { } + + Var va(aPair); + assert ("{ 0 : null }" == va.convert()); + + aPair = Pair(4, "123"); + assert ("123" == aPair.second()); + + va = aPair; + assert ("{ 4 : \"123\" }" == va.convert()); + + int i = 1; + std::string s = "2"; + Pair iPair(i, s); + assert (1 == iPair.first()); + assert ("2" == iPair.second()); + + Pair sPair(s, i); + assert ("2" == sPair.first()); + assert (1 == sPair.second()); + + std::pair p = std::make_pair(i, s); + Pair pPair(p); + assert (1 == pPair.first()); + assert ("2" == pPair.second()); + + Var vp(pPair); + assert ("{ 1 : \"2\" }" == vp.convert()); + + Var vs(sPair); + assert ("{ \"2\" : 1 }" == vs.convert()); +} + + void VarTest::testArrayToString() { std::string s1("string"); @@ -2019,7 +2064,7 @@ void VarTest::testArrayToString() s16.push_back(s2); Var a1(s16); std::string res = a1.convert(); - std::string expected("[ 'string', 23 ]"); + std::string expected("[ \"string\", 23 ]"); assert (res == expected); } @@ -2032,8 +2077,7 @@ void VarTest::testStructToString() aStruct["Age"] = 1; Var a1(aStruct); std::string res = a1.convert(); - std::string expected = "{ 'Age' : 1, 'First Name' : 'Junior', 'Last Name' : 'POCO' }"; -; + std::string expected = "{ \"Age\" : 1, \"First Name\" : \"Junior\", \"Last Name\" : \"POCO\" }"; assert (res == expected); } @@ -2057,14 +2101,14 @@ void VarTest::testArrayOfStructsToString() Var a1(s16); std::string res = a1.convert(); std::string expected = "[ " - "{ 'Age' : 1, 'First Name' : 'Junior', 'Last Name' : 'POCO' }, " - "{ 'Age' : 100, 'First Name' : 'Senior', 'Last Name' : 'POCO' }, " + "{ \"Age\" : 1, \"First Name\" : \"Junior\", \"Last Name\" : \"POCO\" }, " + "{ \"Age\" : 100, \"First Name\" : \"Senior\", \"Last Name\" : \"POCO\" }, " "[ " - "{ 'Age' : 1, 'First Name' : 'Junior', 'Last Name' : 'POCO' }, " - "{ 'Age' : 100, 'First Name' : 'Senior', 'Last Name' : 'POCO' }, " + "{ \"Age\" : 1, \"First Name\" : \"Junior\", \"Last Name\" : \"POCO\" }, " + "{ \"Age\" : 100, \"First Name\" : \"Senior\", \"Last Name\" : \"POCO\" }, " "[ " - "{ 'Age' : 1, 'First Name' : 'Junior', 'Last Name' : 'POCO' }, " - "{ 'Age' : 100, 'First Name' : 'Senior', 'Last Name' : 'POCO' } " + "{ \"Age\" : 1, \"First Name\" : \"Junior\", \"Last Name\" : \"POCO\" }, " + "{ \"Age\" : 100, \"First Name\" : \"Senior\", \"Last Name\" : \"POCO\" } " "] ] ]"; assert (res == expected); @@ -2090,8 +2134,8 @@ void VarTest::testStructWithArraysToString() aStruct["Address"] = addr; Var a2(aStruct); std::string res = a2.convert(); - std::string expected = "{ 'Address' : { 'Country' : 'Carinthia', 'Number' : 4, 'Street' : 'Unknown' }, " - "'Age' : 1, 'First Name' : 'Junior', 'Last Name' : [ 'string', 23 ] }"; + std::string expected = "{ \"Address\" : { \"Country\" : \"Carinthia\", \"Number\" : 4, \"Street\" : \"Unknown\" }, " + "\"Age\" : 1, \"First Name\" : \"Junior\", \"Last Name\" : [ \"string\", 23 ] }"; assert (res == expected); } @@ -2435,6 +2479,7 @@ CppUnit::Test* VarTest::suite() CppUnit_addTest(pSuite, VarTest, testIsStruct); CppUnit_addTest(pSuite, VarTest, testIsArray); CppUnit_addTest(pSuite, VarTest, testArrayIdxOperator); + CppUnit_addTest(pSuite, VarTest, testDynamicPair); CppUnit_addTest(pSuite, VarTest, testDynamicStructBasics); CppUnit_addTest(pSuite, VarTest, testDynamicStructString); CppUnit_addTest(pSuite, VarTest, testDynamicStructInt); diff --git a/Foundation/testsuite/src/VarTest.h b/Foundation/testsuite/src/VarTest.h index fd903dea7..1714f40a0 100644 --- a/Foundation/testsuite/src/VarTest.h +++ b/Foundation/testsuite/src/VarTest.h @@ -72,6 +72,7 @@ public: void testIsStruct(); void testIsArray(); void testArrayIdxOperator(); + void testDynamicPair(); void testDynamicStructBasics(); void testDynamicStructString(); void testDynamicStructInt();