2012-08-31

SCIP in C++11 ― 2章書き直し!

2章書きなおし!

リストの内部表現として、STLlistC++11tupleを、
なるべくプリミティブに使って、
STLの機能をできる限り活用しようとしてきたが、
2.3.2節の実装にかかり限界が来たらしい。

柔軟なメソッドやalgorithmが多様に使えるlistや、
静的リスト限定ながら型の自由度が大きいtupleは、
それぞれに魅力的だったのだが、listは型の自由度が小さく、tupleは動的生成に弱い。
で、2.3.2節で構文解析が始まり、多様な型のデータを格納した複雑な木を、
動的に生成しなければならない状況に入って、お手上げ状態に。

2.3.2節だけならまだしも、構文解析はこの本の主要部なだけに、
ここでしっかり実装できなければならない。
う~ん、listtupleを使うのはここまでか。
特にtupleは散々苦労しただけに、ここでやめるのも惜しいが、
LINK
オブジェクト指向における
再利用のための
デザインパターン
(GoF)
苦労した分わかったことも多くて、ここまででも十分財産になった。

2.1.3で痛感させられたように、適切な抽象の壁が設定されている限り、
内部表現はなんでもいいのだ。
動的な木の生成か~、なんて言ったっけこういうの、
大昔勉強したGoFをもう一度見直す。あーそうだ、Compositeパターン
使う必要に迫られたことはなかったから、発想になかったわ。
Flyweightパターンも考慮する必要があるかもだが、
とりあえずこれで行こう。
boost graph libraryとかまで言い出すと大仰すぎるしな。
関数型プログラミングとSTLにこだわるあまり、
C++のクラスを作る事自体を、拒絶してたところもあった。
つくづく自らの硬直した発想力が嫌になる。

ただCompositeパターンは、複雑な木の生成・破棄に関してのメモリマネジメントが、
メモリリークを防ぐためにとても重要。これは手じゃやりきれんので、
今まであまり使ったことないスマートポインタが必須だなこりゃ。
STLauto_ptrとかを元に、参照カウントとか実装しないといけないのかなあ、
と一時途方に暮れたが、よく見ればC++11にはshared_ptrがあるわけで、
これは参照カウントあるじゃん。auto_ptrはむしろdeprecatedなのか。

これで一気に楽になった~、shared_ptrすげー!もう普通のポインタに戻れないかもw
完全なガベージコレクションとはいかないまでも、
自動ムーブコンストラクションとかも多分効いてるだろうから、
多少のマネジメントミスはかなり吸収してくれてるんじゃないかこれ。
shared_ptrを安全に使いこなせてる自信はまだないが、
悩みがだいぶ減ったのは確かだわ。C++11の表現力すげー、感動。
てか本当にすごいのはboostで、boost使いは前から知ってたんだろうが、
自らの不勉強に恥じ入ることしきり。

で、2章のコードはほとんど全部書きなおし。
リスト成分の内部表現はとりあえずstringで、
値の取り出しには別のテンプレートラッパvalue関数を実装する。
まー効率は度外視。これで行けるところまで行ってみよう。
でも基本機能を抽象の壁のむこうに追いやると、思ったより修正箇所が少ないし、
コードもコンパクトでわかりやすくなった。抽象の壁恐るべし。
もっと早くCompositeパターンに気づくべきだった。

基本機能のコードは以下の通り。これで2.2節までうまく行った(2.2.4節除く)。
これを使って、今までの2章のブログ記事もすべて書き直し。
だってヘタクソコードをいつまでも晒すのは恥ずかしいんだもん。

-----
//-------representation of list (Composite pattern) ----------
typedef string LeafItemType;
const LeafItemType nullLeafItem(LeafItemType(""));

class ListTree
{
public:
    virtual ~ListTree(void){}
    const shared_ptr<ListTree> getParentList(void) const{
        return(this->_predecessor);}
    virtual const LeafItemType getItem(void)const{
        return(this->item);}
    virtual const bool isList(void)const{
        return(false);}
    virtual void addElement(const shared_ptr<ListTree>&){
        cerr<<"You cannot add a leaf to a leaf."<<endl;
        exit(1);
    }
    virtual const shared_ptr<ListTree> carElement() const{
        cerr<<"You cannot take the car of a leaf."<<endl;
        exit(1);
    }
    virtual void removeFirstElement(){
        cerr<<"You cannot remove the first element of a leaf."<<endl;
        exit(1);
    }
    virtual const int length(void)const{
        cerr<<"You cannot get the length of a leaf."<<endl;
        exit(1);
    }
    virtual const bool isNull(void)const{return(false);}
    void changePredecessor(const shared_ptr<ListTree>& _predecessorNew){
        this->_predecessor=_predecessorNew;}
    virtual const string getExpression(void) const{
        return(this->getItem());}
    virtual const int getInt(void)const{
        return(stoi(this->getItem()));}
    virtual const double getDouble(void)const{
        return(stod(this->getItem()));}
protected:
    shared_ptr<ListTree> _me;
    ListTree(void)=delete;
    ListTree(shared_ptr<ListTree> _predecessorIn,
             const LeafItemType& itemIn=nullLeafItem):
        _me(nullptr),
        _predecessor(_predecessorIn),
        item(itemIn)
    {
        _me=make_shared<ListTree>(*this);
    }
    
private:
    shared_ptr<ListTree> _predecessor;
    LeafItemType item;
};

class CompositeList:public ListTree
{
public:
    CompositeList(const shared_ptr<ListTree>& _predecessorIn=nullptr):
        ListTree(_predecessorIn),_listTrees(0){}
    virtual ~CompositeList(void){
        if(! this->_listTrees.empty()){
            for_each(this->_listTrees.begin(),this->_listTrees.end(),
                     [](shared_ptr<ListTree> _element){
                         if(_element && _element.unique()){
                             delete _element.get();
                         }
                     });
        }
    }
    virtual const bool isList(void)const{return(true);}
    virtual void addElement(const shared_ptr<ListTree>& _element)
    {
        this->_listTrees.push_front(_element);
        _element->changePredecessor(this->_me);
    }
    virtual const shared_ptr<ListTree> carElement() const{
        return(this->_listTrees.front());
    }
    virtual void removeFirstElement(){this->_listTrees.pop_front();}
    virtual const int length(void)const{return(this->_listTrees.size());}
    virtual const bool isNull(void)const{return(this->_listTrees.empty());}
    virtual const string getExpression(void)const{
        string returnString("(");
        for_each(this->_listTrees.begin(),this->_listTrees.end(),
                 [&returnString](const shared_ptr<ListTree> _element){
                     returnString+=_element->getExpression()+" ";
                 });
        if(!this->isNull()){returnString.pop_back();}
        returnString.push_back(')');
        return(returnString);
    }
    virtual const int getInt(void)const{
        cerr<<"requiring an integer value for a list."<<endl;
        return(numeric_limits<int>::quiet_NaN());}
    virtual const double getDouble(void)const{
        cerr<<"requiring a double value for a list."<<endl;
        return(numeric_limits<double>::quiet_NaN());}
private:
    list<shared_ptr<ListTree>> _listTrees;
};

class Leaf:public ListTree
{
public:
    Leaf(void)=delete;
    Leaf(const LeafItemType& itemIn):ListTree(nullptr,itemIn){}
    virtual ~Leaf(void){}
};
   


   
//---------abstraction barrier---------
typedef shared_ptr<ListTree> List;

// print list
const string listString(const List& _listTree)
{return(_listTree->getExpression());}

// get value expression
//for string
template <typename ReturnType>
const ReturnType value(const List& _listTree)
{return(_listTree->getItem());}
//for list
template<>
const List value<List>(const List& _listTree)
{return(_listTree);}
//for int
template<>
const int value<int>(const List& _listTree)
{return(_listTree->getInt());}
//for double
template<>
const double value<double>(const List& _listTree)
{return(_listTree->getDouble());}


const List makeCopyList(const List& _listTree)
{
    return(make_shared<CompositeList>
           (*dynamic_pointer_cast<CompositeList>(_listTree)));
}

template<typename ItemType>
const List makeLeaf(const ItemType& x)
{
    ostringstream tmpSStreamX;
    tmpSStreamX<<setprecision(16)<<x;
    return(make_shared<Leaf>(tmpSStreamX.str()));
}

template <typename ReturnType,typename ArgType>
const List leafMap(const function<ReturnType(ArgType)> procedure,
                   const List _leaf)
{
    return(makeLeaf(procedure(value<ArgType>(_leaf))));
}

const List cons(void){return(make_shared<CompositeList>());}

template <typename ItemTypeX>
const List cons(const ItemTypeX& x, const List& _yList)
{
    List _yListCopy(makeCopyList(_yList));
    _yListCopy->addElement(makeLeaf(x));
    return(_yListCopy);
}
template<>
const List cons<List>(const List& _xList,const List& _yList){
    List _xListCopy(_xList);
    List _yListCopy(makeCopyList(_yList));
    _yListCopy->addElement(_xListCopy);
    return(_yListCopy);
}

template <typename ItemTypeX>
const List cons(const ItemTypeX& x)
{return(cons(x,cons()));}

template <typename ItemTypeX,typename ItemTypeY>
const List cons(const ItemTypeX& x,const ItemTypeY& y)
{return(cons(x,cons(y)));}

const List car(const List& _listTree)
{
    return(_listTree->carElement());
}

const List cdr(const List& _listTree)
{
    if(!_listTree->isList()){return(cons());}
    List _cdrListTree(makeCopyList(_listTree));
    _cdrListTree->removeFirstElement();
    return(_cdrListTree);
}

const List makeList(void)
{
    return(cons());
}
template<typename ListType1, typename ... ListTypes>
const List makeList(const ListType1& element1, ListTypes... elements)
{
    return(cons(element1,makeList(elements...)));
}

// size of a list
const int length(const List& _listTree)
{
    return(_listTree->length());
}

// null?
const bool isNull(const List& _listTree)
{
    return(_listTree->isNull());
}

// pair?
const bool isPair(const List& _listTree)
{
    return(_listTree->isList());
}


//---------abstraction barrier---------
const List cadr(const List& listIn)
{
    return(car(cdr(listIn)));
}

const List caddr(const List& listIn)
{
    return(car(cdr(cdr(listIn))));
}

0 件のコメント :

コメントを投稿