Poco::DynamicAny

Poco::DynamicAny を紹介します。

Poco::DynamicAny は、種々の型の値を保持し、型間の変換を透過的に行ってくれます。
意図しないデータロスが無いように、特に数値型どうしの変換時の値の制限や符号変換時に、直感的で妥当な変換が行われるようになっています。

浮動小数点型から整数型への変換や、double から float への変換時は、精度が落ちます。
文字列と char 間の変換で、文字列が1文字以上の時、文字はトランケートされます。空の文字列は ‘\0’ に変換され、空でない文字列は最初の1文字になります。
Boolean 型の変換規則は次のようになります:
・文字列 “false”(大文字小文字とも), “0”, “” は false、それ以外の文字列は true。
・整数の 0 は false、それ以外は true。
・浮動小数点型は、プラットフォームの最小値のとき false、それ以外は true。
POD 型と、もしくは Poco::DynamicAny 間の算術操作は、次の条件付きでサポートされています:
・std::string と const char*:’+’, ‘+=’
・整数型と浮動小数点型:’+’, ‘+=’, ‘-‘, ‘-=’, ‘*’, ‘*=’ , ‘/’, ‘/=’
・整数型:’++’, ‘–‘(前置、後置とも)
・それ以外の算術操作では、 Poco::InvalidArgumentException が飛ぶ。

DynamicAnyTest.cpp

・構造体 TestTypes 内の1つの型のデータを設定し、それを他の型に変換。
・CreateTestDynamicAnyInstances<>() というテンプレート関数を再帰的に呼び出し、TestTypes 内の
 全ての型に対応。
・eTypeBool と eTypeString について特殊化を定義。
 (eTypeString の特殊化関数から eTypeBool の特殊化関数を呼ぶので、 eTypeBool の特殊化を
  eTypeString の前に書く必要があることに注意)

#include <Poco/DynamicAny.h>
#include <Poco/TypeList.h>
 
#include <string>
#include <typeinfo>
#include <algorithm>
 
#include "ScopedLogMessage.h"
#include "PrepareConsoleLogger.h"
 
enum EMyType {	eTypeChar = 0
	,	eTypeInt8
	,	eTypeUInt8
	,	eTypeInt16
	,	eTypeUInt16
	,	eTypeInt32
	,	eTypeUInt32
	,	eTypeInt64
	,	eTypeUInt64
	,	eTypeFloat
	,	eTypeDouble
	,	eTypeString
	,	eTypeBool	};
 
const std::string kMyTypeName[] = {
		"char"
	,	"Poco::Int8"
	,	"Poco::UInt8"
	,	"Poco::Int16"
	,	"Poco::UInt16"
	,	"Poco::Int32"
	,	"Poco::UInt32"
	,	"Poco::Int64"
	,	"Poco::UInt64"
	,	"float"
	,	"double"
	,	"std::string"
	,	"bool"	};
 
const int kNumMyTypeKind = sizeof(kMyTypeName)/sizeof(kMyTypeName[0]);
 
struct TestTypes
{
	char		c;
	Poco::Int8	i8;
	Poco::UInt8	u8;
	Poco::Int16	i16;
	Poco::UInt16	u16;
	Poco::Int32	i32;
	Poco::UInt32	u32;
	Poco::Int64	i64;
	Poco::UInt64	u64;
	float		f;
	double		d;
	std::string	s;
	bool		b;
};
 
typedef Poco::TypeListType<
	char
,	Poco::Int8
,	Poco::UInt8
,	Poco::Int16
,	Poco::UInt16
,	Poco::Int32
,	Poco::UInt32
,	Poco::Int64
,	Poco::UInt64
,	float
,	double
,	std::string
,	bool
	>::HeadType MyTypeList;
 
class TestDynamicAnyBase
{
public:
	TestDynamicAnyBase()
	{
	}
	virtual ~TestDynamicAnyBase()
	{
	}
	virtual std::string isNative(const char* typeidStr) = 0;
};
 
template <EMyType N>
class TestDynamicAny : public TestDynamicAnyBase
{
	typedef typename Poco::TypeGetter<N, MyTypeList>::HeadType	MyType;
 
public:
	TestDynamicAny(TestTypes& dest, MyType src) : TestDynamicAnyBase()
	{
		Poco::DynamicAny a = src;
 
		a.convert(dest.i8);
		a.convert(dest.u8);
		a.convert(dest.i16);
		a.convert(dest.u16);
		a.convert(dest.i32);
		a.convert(dest.u32);
		a.convert(dest.i64);
		a.convert(dest.u64);
		a.convert(dest.f);
		a.convert(dest.d);
		a.convert(dest.b);
		a.convert(dest.c);
		a.convert(dest.s);
	}
	std::string isNative(const char* typeidStr)
	{
		return std::string((std::string(typeid(MyType).name()) == typeidStr) ? "*":" ");
	}
};
 
template<EMyType N>
void CreateTestDynamicAnyInstances(std::vector<TestDynamicAnyBase*>& vec, TestTypes* dest)
{
	typedef typename Poco::TypeGetter<N, MyTypeList>::HeadType	MyType;
 
	vec[N] = new TestDynamicAny<N>(dest[N], static_cast<MyType>('A'-N));
	CreateTestDynamicAnyInstances<static_cast<EMyType>(N+1)>(vec, dest);	// recursive call
}
 
template<>
void CreateTestDynamicAnyInstances<eTypeBool>(std::vector<TestDynamicAnyBase*>& vec, TestTypes* dest)
{
	vec[eTypeBool] = new TestDynamicAny<eTypeBool>(dest[eTypeBool], true);
}
 
template<>
void CreateTestDynamicAnyInstances<eTypeString>(std::vector<TestDynamicAnyBase*>& vec, TestTypes* dest)
{
	vec[eTypeString] = new TestDynamicAny<eTypeString>(dest[eTypeString], std::string("54"));
	CreateTestDynamicAnyInstances<static_cast<EMyType>(eTypeString+1)>(vec, dest);	// recursive call
}
 
class DeleteTestDynamicAnyInstance
{
public:
	void operator () (TestDynamicAnyBase* ptr)
	{
		delete ptr;
	}
};
 
int main(int /*argc*/, char** /*argv*/)
{
	PrepareConsoleLogger logger(Poco::Logger::ROOT, Poco::Message::PRIO_INFORMATION);
 
	ScopedLogMessage msg("DynamicAnyTest ", "start", "end");
 
	TestTypes dest[kNumMyTypeKind];
	std::vector<TestDynamicAnyBase*> vec(kNumMyTypeKind);
 
	CreateTestDynamicAnyInstances<eTypeChar>(vec, &dest[0]);
 
	std::string resultStr[kNumMyTypeKind];
	for(int i=0; i<kNumMyTypeKind; ++i)
	{
		resultStr[eTypeChar]	+= Poco::format("%3?i%s   ", dest[i].c,   vec[i]->isNative(typeid(char).name()));
		resultStr[eTypeInt8]	+= Poco::format("%3?i%s   ", dest[i].i8,  vec[i]->isNative(typeid(Poco::Int8).name()));
		resultStr[eTypeUInt8]	+= Poco::format("%3?i%s   ", dest[i].u8,  vec[i]->isNative(typeid(Poco::UInt8).name()));
		resultStr[eTypeInt16]	+= Poco::format("%3?i%s   ", dest[i].i16, vec[i]->isNative(typeid(Poco::Int16).name()));
		resultStr[eTypeUInt16]	+= Poco::format("%3?i%s   ", dest[i].u16, vec[i]->isNative(typeid(Poco::UInt16).name()));
		resultStr[eTypeInt32]	+= Poco::format("%3?i%s   ", dest[i].i32, vec[i]->isNative(typeid(Poco::Int32).name()));
		resultStr[eTypeUInt32]	+= Poco::format("%3?i%s   ", dest[i].u32, vec[i]->isNative(typeid(Poco::UInt32).name()));
		resultStr[eTypeInt64]	+= Poco::format("%3?i%s   ", dest[i].i64, vec[i]->isNative(typeid(Poco::Int64).name()));
		resultStr[eTypeUInt64]	+= Poco::format("%3?i%s   ", dest[i].u64, vec[i]->isNative(typeid(Poco::UInt64).name()));
		resultStr[eTypeFloat]	+= Poco::format("%6.2hf%s",  dest[i].f,   vec[i]->isNative(typeid(float).name()));
		resultStr[eTypeDouble]	+= Poco::format("%6.2f%s",   dest[i].d,   vec[i]->isNative(typeid(double).name()));
		resultStr[eTypeString]	+= Poco::format("%4s%s  ",   Poco::format("\"%s\"", dest[i].s), vec[i]->isNative(typeid(std::string).name()));
		resultStr[eTypeBool]	+= Poco::format("%3b%s   ",  dest[i].b,   vec[i]->isNative(typeid(bool).name()));
	}
 
	std::for_each(vec.begin(), vec.end(), DeleteTestDynamicAnyInstance());
 
	for(int i=0; i<kNumMyTypeKind; ++i)
	{
		msg.Message(Poco::format("%13s %s", kMyTypeName[i], resultStr[i]));
	}
	msg.Message("                "
				"(NOTE: item with trailing '*' indicates it's the source)");
 
	return 0;
}

Results of execution

[0] DynamicAnyTest start
[0]          char  65*    64     63     62     61     60     59     58     57     56     55     53      1    
[0]    Poco::Int8  65     64*    63     62     61     60     59     58     57     56     55     54      1    
[0]   Poco::UInt8  65     64     63*    62     61     60     59     58     57     56     55     54      1    
[0]   Poco::Int16  65     64     63     62*    61     60     59     58     57     56     55     54      1    
[0]  Poco::UInt16  65     64     63     62     61*    60     59     58     57     56     55     54      1    
[0]   Poco::Int32  65     64     63     62     61     60*    59     58     57     56     55     54      1    
[0]  Poco::UInt32  65     64     63     62     61     60     59*    58     57     56     55     54      1    
[0]   Poco::Int64  65     64     63     62     61     60     59     58*    57     56     55     54      1    
[0]  Poco::UInt64  65     64     63     62     61     60     59     58     57*    56     55     54      1    
[0]         float  65.00  64.00  63.00  62.00  61.00  60.00  59.00  58.00  57.00  56.00* 55.00  54.00   1.00 
[0]        double  65.00  64.00  63.00  62.00  61.00  60.00  59.00  58.00  57.00  56.00  55.00* 54.00   1.00 
[0]   std::string  "A"   "64"   "63"   "62"   "61"   "60"   "59"   "58"   "57"   "56"   "55"   "54"*  "true"   
[0]          bool   1      1      1      1      1      1      1      1      1      1      1      1      1*   
[0]                 (NOTE: item with trailing '*' indicates it's the source)
[0] DynamicAnyTest end

Downloads

ここをクリックすると、makefile や VC++ プロジェクトなど一式がダウンロードできます。
(2013.05.31 updated)
・2010年6月21日からのダウンロード数:767

Subversion

・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。

Reference

http://pocoproject.org にある Types のプレセンテーション。(PDF)

Powered by POCO Copyright © 2010 Round Square Inc. All rights reserved.


Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>