2013年9月6日金曜日

C++でvar型変数を作ってみた。 その2

以前作ったC++のvar型変数ですが、よくがんがえたら配列の長さとかクリアとか列挙ができず、操作性が悪いことに気づきました。そこで配列の操作関数を追加してみました。

これで、ひとつの変数で、int,文字列、配列、多次元配列、連想配列、ができます。
これに伴い、配列と連想配列の明確な区別をしました。
配列は要素識別子に0から始まり最大要素数-1をとる連続したデータ列。
連想配列は任意の文字列や数値をとる配列
==や!=でnullと0と""と空配列を同じに扱うかどうか悩みます。
var変数の値の設定取得、サイズ取得、同値判定、初期化、破棄、要素選択など基本動作はすべてできます。
あとは+や-など、演算子をオーバーロードすれば完成。

だんだん複雑になってきたのでテストコードを追加しました。


------------------------------
varient.cpp
------------------------------
#include <stdio.h>
#include "variant.h"

#if defined(_WIN32) && !defined(__GNUC__)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif


static var var_null;

var::var()
{
clear();
type=0;
m_val=0;
}

var::var(int v)
{
clear();
type=VAR_TYPE_INT;
m_val=v;
}

var::var(const char*str)
{
var((std::string)str);
}

var::var(std::string str)
{
clear();
type=VAR_TYPE_STRING;
m_str=str;
}


var::var(var& val)
{
(*this)=val;
}


var::~var()
{
clear();
}

void var::clear()
{
var* ret;
std::map<std::string,var*>::iterator ite;

ite=m_map.begin();
while( ite != m_map.end() )
{
ret=(*ite).second;
delete ret;
ite++;
}
type=0;
m_val=0;
m_str.clear();
m_map.clear();

//m_min_array=0;
m_max_array=0;
m_is_array=false;
}

var& var::operator[](const char* str)
{
if(str==NULL){
return var_null;
}
return operator[]((std::string)str);
}

var& var::operator[](std::string str)
{
var* ret=&var_null;

if(type!=0 && type!=VAR_TYPE_MAP){
return *ret;
}

switch(type){
case 0:
type=VAR_TYPE_MAP;
m_is_array=false;
case VAR_TYPE_MAP:
m_is_array=false;
ret=m_map[str];
if(ret==NULL){
ret=new var();
m_map[str]=ret;
}
break;
}
return *ret;
}

var& var::operator[](int v)
{
var* ret=&var_null;
char tmp[64];

tmp[0]=0;
sprintf(tmp,"%d",v);
std::string str=tmp;

if(type!=0 && type!=VAR_TYPE_MAP){
return *ret;
}

switch(type){
case 0:
type=VAR_TYPE_MAP;
m_is_array=true;
case VAR_TYPE_MAP:
ret=m_map[str];
if(ret==NULL){
ret=new var();
m_map[str]=ret;
}
if(m_is_array){
if(v<0)m_is_array=false;
if(m_max_array<v+1)m_max_array=v+1;
}
break;
}
return *ret;
}

void var::tumeru()
{
if(type!=VAR_TYPE_MAP)return;

std::map<std::string,var*>::iterator ite;
std::map<std::string,var*>::iterator old_ite;
bool f_del=false;

type=VAR_TYPE_MAP;
ite=m_map.begin();
while( ite != m_map.end() )
{
var* v;
v=(*ite).second;
if(v->type==0){
f_del=true;
}
old_ite=ite;
ite++;
if(f_del){
m_map.erase(old_ite);
}
f_del=false;
}
}

var& var::at(int n)
{
if(type!=VAR_TYPE_MAP || n<0){
return var_null;
}

tumeru();

std::map<std::string,var*>::iterator ite;
int ct=0;

ite=m_map.begin();
while( ite != m_map.end() )
{
if(ct==n)return *(*ite).second;
ite++;
ct++;
}

return var_null;
}


var& var::operator =(std::string str)
{
clear();

type=VAR_TYPE_STRING;
m_str=str;
return *this;
}

var& var::operator =(int val)
{
clear();

type=VAR_TYPE_INT;
m_val=val;

// 0 is as same as null
//if(val==0){
// type=VAR_TYPE_NULL;
// m_val=0;
//}
return *this;
}


var& var::operator =(var& val)
{
var* ret;
std::map<std::string,var*>::iterator ite;

//clear all
clear();

switch(val.type){
case VAR_TYPE_NULL:
break;
case VAR_TYPE_INT:
type=VAR_TYPE_INT;
m_val=val.m_val;
if(m_val==0){
type=0;
}
break;
case VAR_TYPE_STRING:
type=VAR_TYPE_STRING;
m_str=val.m_str;
break;
case VAR_TYPE_MAP:
std::map<std::string,var*>::iterator ite;
type=VAR_TYPE_MAP;
ite=val.m_map.begin();
while( ite != val.m_map.end() )
{
m_map[(*ite).first]=new var();
*(m_map[(*ite).first])=*(*ite).second;
ite++;
}
break;
}
return *this;
}

var::operator std::string()
{
switch(type){
case 0:
return "null";
case VAR_TYPE_STRING:
return m_str;
case VAR_TYPE_INT:
return toString();
case VAR_TYPE_MAP:
return "objrct";
}
return "broken";
}


var::operator int()
{
switch(type){
case 0:
return 0;
case VAR_TYPE_INT:
return m_val;
case VAR_TYPE_STRING:
return toInt();
}
return -1;
}

const char* var::pchar()
{
switch(type){
case 0:
return "null";
case VAR_TYPE_STRING:
return m_str.c_str();
case VAR_TYPE_INT:
return toString().c_str();
case VAR_TYPE_MAP:
return "objrct";
}
return "broken";
}

int var::toInt()
{
int ret=0;
switch(type){
case 0:
return 0;
case VAR_TYPE_INT:
return m_val;
case VAR_TYPE_STRING:
ret=-1;
sscanf(m_str.c_str(),"%d",&ret);
return ret;
}
return ret;
}

std::string var::toString()
{
std::string ret;
switch(type){
case 0:
return "0";
case VAR_TYPE_INT:
char tmp[64];
tmp[0]=0;
sprintf(tmp,"%d",m_val);
ret=tmp;
return ret;
case VAR_TYPE_STRING:
return m_str;
}
return ret;
}


bool var::operator ==(int v)
{
switch(type){
case 0:
if(v==0)return true;
return false;
}
return false;
}

bool var::operator !=(int v)
{
switch(type){
case 0:
if(v==0)return false;
return true;
}
return true;
}

bool var::operator ==(var& val)
{
switch(type){
case 0:
if(val.type==0)return true;
if(val.type==VAR_TYPE_INT && val.m_val==0)return true;
return false;
case VAR_TYPE_INT:
if(val.type==VAR_TYPE_INT && m_val==val.m_val)return true;
return false;
case VAR_TYPE_STRING:
if(val.type==VAR_TYPE_STRING && m_str==val.m_str)return true;
return false;
case VAR_TYPE_MAP:
//no implement
return false;
}
return false;
}

bool var::operator !=(var& val)
{
switch(type){
case 0:
if(val.type==0)return false;
if(val.type==VAR_TYPE_INT && val.m_val==0)return false;
return true;
case VAR_TYPE_INT:
if(val.type==VAR_TYPE_INT && m_val==val.m_val)return false;
return true;
case VAR_TYPE_STRING:
if(val.type==VAR_TYPE_STRING && m_str==val.m_str)return false;
return true;
case VAR_TYPE_MAP:
//no implement
return true;
}
return true;
}

int var::length()
{
int ret=0;
switch(type){
case 0:
return 0;
case VAR_TYPE_STRING:
return m_str.length();
case VAR_TYPE_INT:
if(m_val>=0)return m_val;
return -m_val;
case VAR_TYPE_MAP:
if(m_is_array){
return m_max_array;
}
tumeru();
ret=m_map.size();
return ret;
}
return ret;
}



------------------------------
varient.h
------------------------------

#include <string>
#include <map>

#define VAR_TYPE_NULL 0
#define VAR_TYPE_INT 1
#define VAR_TYPE_STRING 2
#define VAR_TYPE_MAP 3
#define VAR_TYPE_LIST 4


class var{
public:
var();
var(int v);
var(const char* str);
var(std::string str);
var(var& val);

void clear();

virtual ~var();

var& operator[](std::string str);
var& operator[](const char* str);
var& operator[](int);
var& at(int);

var& operator =(std::string str);
var& operator =(int val);
var& operator =(var& val);

bool operator ==(int);
bool operator !=(int);

bool operator ==(var& val);
bool operator !=(var& val);


// you should implement
//var& operator +=(std::string str);
//var& operator +=(const char* str);
//var& operator +=(int val);
//var& operator +=(var& val);

// you should implement
//var operator +(std::string str);
//var operator +(const char* str);
//var operator +(int val);
//var operator +(var& val);


operator std::string();
operator int();

int toInt();
std::string toString();

int length();
const char* pchar();
private:
void tumeru();

private:

int type;

std::map<std::string,var*> m_map;
std::string m_str;
int m_val;

int m_max_array;
bool m_is_array;
};



------------------------------
varient.cpp
------------------------------

#include <stdio.h>
#include "variant.h"

#if defined(_WIN32) && !defined(__GNUC__)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif

int main(int argc,char* argv[])
{
#if defined(_WIN32) && !defined(__GNUC__)
// _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_WNDW);
// _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
// _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_WNDW);
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
#endif

var a,b,c,d,e,f;

var g=5;
var h="hoge";
var j=(std::string)"hoge";
var k=j;

std::string str;
int i=-1;


//null testing
if(a==NULL)printf("a is null  #### OK ####\n");
else printf("a is NOT null#### NG ####\n");

if(a!=NULL)printf("a is NOT null #### NG ####\n");
else printf("a is null#### OK ####\n");

a["key"]="value";
a[5]=10;

if(a==NULL)printf("a is null #### NG ####\n");
else printf("a is NOT null#### OK ####\n");

if(a!=NULL)printf("a is NOT null#### OK ####\n");
else printf("a is null#### NG ####\n");

//int testing
i=a[5];
printf("i=%d\n",i);
if(i==10)printf("#### OK ####\n");
else printf("#### NG ####\n");


// redbrack testing
b["hoge"]=a;
c=b;
d=c["hoge"];

if(a["key"]==e)printf("a[key]is e #### NG ####\n");
else printf("a[key]is NOT e #### OK ####\n");

if(a["key"]!=e)printf("a[key]is NOT e #### OK ####\n");
else printf("a[key]is e #### NG ####\n");

if(a[5]==f)printf("a[key]is f #### NG ####\n");
else printf("a[key]is NOT f #### OK ####\n");

if(a[5]!=f)printf("a[key]is NOT f #### OK ####\n");
else printf("a[key]is f #### NG ####\n");


e="value";
f=10;
printf("str=>>%s<<\n",((std::string)e).c_str());
if((std::string)e=="value")printf("####  OK ####\n");
else printf("####  NG ####\n");

printf("str=>>%s<<\n",e.pchar());
if((std::string)e.pchar()=="value")printf("#### OK ####\n");
else printf("####  NG ####\n");

if(a["key"]==e)printf("a[key]is e #### OK ####\n");
else printf("a[key]is NOT e #### NG ####\n");

if(a[5]==f)printf("a[key]is f #### OK ####\n");
else printf("a[key]is NOT f #### NG ####\n");


str=a["key"];
a["key"]="hoge!!!!";
printf("str=>>%s<<\n",str.c_str());
if(str=="value")printf("#### OK ####\n");
else printf("#### NG ####\n");

str=d["key"];
printf("str=>>%s<<\n",str.c_str());
if(str=="value")printf("#### OK ####\n");
else printf("#### NG ####\n");

str=a["key"];
printf("str=>>%s<<\n",str.c_str());
if(str=="hoge!!!!")printf("#### OK ####\n");
else printf("#### NG ####\n");

str=a[5];
printf("str=>>%s<<\n",str.c_str());
if(str=="10")printf("#### OK ####\n");
else printf("#### NG ####\n");

a["key"]="123";
i=a["key"];
printf("i=%d\n",i);
if(i=123)printf("#### OK ####\n");
else printf("#### NG ####\n");

a["key"]=0;
i=a["key"];
printf("i=%d\n",i);
if(i==0)printf("#### OK ####\n");
else printf("#### NG ####\n");


// clear testing
a["key"]=100;
a["key"].clear();
i=a["key"];
printf("i=%d\n",i);
if(i==0)printf("#### OK ####\n");
else printf("#### NG ####\n");


// length tesintg
a.clear();
if(a==NULL)printf("#### OK ####\n");
else printf("#### NG ####\n");

i=a.length();
printf("a.length()=%d\n",i);
if(i==0)printf("#### OK ####\n");
else printf("#### NG ####\n");

a=-5;
i=a.length();
printf("a.length()=%d\n",i);
if(i==5)printf("#### OK ####\n");
else printf("#### NG ####\n");

a="";
i=a.length();
printf("a.length()=%d\n",i);
if(i==0)printf("#### OK ####\n");
else printf("#### NG ####\n");

a="abcdefg";
i=a.length();
printf("a.length()=%d\n",i);
if(i==7)printf("#### OK ####\n");
else printf("#### NG ####\n");

a.clear();
a[7]=70;
a[100]=123;
i=a.length();
printf("a.length()=%d\n",i);
if(i==101)printf("#### OK ####\n");
else printf("#### NG ####\n");

a[-1]=123;
i=a.length();
printf("a.length()=%d\n",i);
if(i==3)printf("#### OK ####\n");
else printf("#### NG ####\n");


// multidimensional array testing
a.clear();
a[15][5]=55;
i=a[15].length();
printf("a[15].length()=%d\n",i);
if(i==6)printf("#### OK ####\n");
else printf("#### NG ####\n");

i=a[15][5];
printf("i=%d\n",i);
if(i==55)printf("#### OK ####\n");
else printf("#### NG ####\n");

//erase test
a.clear();
a["sss"]=5;
a["ttt"]=10;
a["uuu"]=20;
a["ttt"].clear();
i=a.length();
printf("i=%d\n",i);
if(i==2)printf("#### OK ####\n");
else printf("#### NG ####\n");

// at() testing
i=a.at(0);
printf("a.at(0)=%d\n",i);
if(i==5 || i==20)printf("#### OK ####\n");
else printf("#### NG ####\n");

i=a.at(1);
printf("a.at(1)=%d\n",i);
if(i==5 || i==20)printf("#### OK ####\n");
else printf("#### NG ####\n");

i=a.at(2);
printf("a.at(2)=%d\n",i);
if(i==0)printf("#### OK ####\n");
else printf("#### NG ####\n");

i=a.length();
printf("i=%d\n",i);
if(i==2)printf("#### OK ####\n");
else printf("#### NG ####\n");

return 0;
}


0 件のコメント:

コメントを投稿