CAnyContainer

gummikana 30.01.04 19:08

Template viritelmä, jonka avulla voi tehdä stl:än containereista tyypittömiä. Pilkottu versio löytyy täältä: http://koti.mbnet.fi/kumikana/soodaus/cpp/CAnyContainer/canycontainer.zip

 Tekstiversio  Arvo: 3 (3 ääntä)  Äänestä: +  -
////////////////////////////////////////////////////////////////
// CAnyContainer
//--------------------------------------------------------------
//
// Lyhyesti CAnyContainer on luokka, jonka avulla voi muuttaa
// STL:än containerit tyypittömiksi, eli niin, että ne hyväksyvät
// minkä tahansa tyyppisiä muuttujia. Alhaalta löytyy kattava
// esimerkki CAnyContainerin käytöstä.
//
// Tämä tiedosto on kolmen tiedoston yhdistelmä, joka toimii
// sellaisenaan, mutta jos oikeasti haluat käyttää
// CAnyContaineria kannattaa nämä tiedostot pilkkoa sopiviin
// header tiedostoihin.
//
// Pilkottu versio löytyy täältä:
// http://koti.mbnet.fi/kumikana/soodaus/cpp/CAnyContainer/canycontainer.zip
//
// täällä voi ihailla koodia:
// http://koti.mbnet.fi/kumikana/soodaus/cpp/CAnyContainer/
//
//
// CAnyContainer käyttää CVarReference luokka kokoelmaa, josta
// olen suhteellisen ylpeä, sillä se on osoittautunut paljon
// hyödyllisemmäksi ja monikäyttöisemmäksi kuin osasin ikinä
// kuvitella. Toinen applikaatio missä olen tätä luokka
// kokoelmaa käyttänyt on CConsole luokka ( siis sen uusin
// versio ). CConsole löytynee täältä:
// http://koti.mbnet.fi/kumikana/soodaus/cpp/CConsole/
//
//--------------------------------------------------------------


// Begin of cvarreference.h
#ifndef INC_CVARREFERENCE_H
#define INC_CVARREFERENCE_H


////////////////////////////////////////////////////////////////
//
// cvarreference.h
//
// Writen 11.01.2004
// by Petri Purho ( pete@markkupurho.fi )
//
// Basicly this is set of classes derived from CVarRefBase class
// used to set values to "any" class. If you want to add your
// own class to the supported classes write a new function
// to the cengstringstream class.
//
////////////////////////////////////////////////////////////////

#include <typeinfo>
#include <string>
#include <sstream>

////////////////////////////////////////////////////////////////

namespace std
{

    // This class here is used to setting values to the types...
    //
    class cengstringstream : public istringstream
    {
    public:
        cengstringstream( openmode mode = in  ) : istringstream( mode ), myStr("") { }
        cengstringstream( const string& str, openmode mode = in ) :
          istringstream( str, mode ), myStr( str ) { }

        //istream& operator>> ( int& val ) { return istringstream::operator>>(val); }
        template< typename _T >
        istream& operator>> ( const _T& val ) const  { return *this; }

        template< typename _T >
        istream& operator>> ( _T& val ) { return *this; }


        istream& operator>> (bool& val ) { return istringstream::operator>>(val); }
        istream& operator>> (short& val ) { return istringstream::operator>>(val); }
        istream& operator>> (unsigned short& val ) { return istringstream::operator>>(val); }
        istream& operator>> (int& val ) { return istringstream::operator>>(val); }
        istream& operator>> (unsigned int& val ) { return istringstream::operator>>(val); }
        istream& operator>> (long& val ) { return istringstream::operator>>(val); }
        istream& operator>> (unsigned long& val ) { return istringstream::operator>>(val); }
        istream& operator>> (float& val ) { return istringstream::operator>>(val); }
        istream& operator>> (double& val ) { return istringstream::operator>>(val); }
        istream& operator>> (long double& val ) { return istringstream::operator>>(val); }
        istream& operator>> (void*& val ) { return istringstream::operator>>(val); }
 
        istream& operator>> (string& sb ) { sb = myStr; return (*this); }
   
    private:
        const string& myStr;
    };
}
////////////////////////////////////////////////////////////////

// The idea of CVarRef classes is that you can create a
// reference to any variable. Be it const or nor. And you can
// change that variables value by a string value. Very handy
// in lots of places. Like the CAnyContainer
//
// The CVarRefBase is a abstract class, that defines the interface
class CVarRefBase
{
public:
    CVarRefBase() { }
    virtual ~CVarRefBase() { }

    virtual void        SetValue( const std::string& value ) = 0;
    virtual std::string GetValue() const = 0;

    virtual std::string GetName() const = 0;
    virtual std::string GetType() const = 0;

    virtual bool        GetConst() const = 0;
};


////////////////////////////////////////////////////////////////

// This is a the basic reference, that actually does something
template< typename _Ty >
class CVarRef : public CVarRefBase
{
public:

   
    CVarRef( const std::string& varname, _Ty& var ) :
      myVariable( var ),
      myVariableName( varname ),
      myVariableType( typeid( var ).name() ),
      myConst( false )
    {
         
    }


    void        SetValue( const std::string& value )
    {
        if ( !myConst )
            std::cengstringstream( value ) >> myVariable;
    }
   
    std::string GetValue() const
    {
        std::stringstream ss;
        ss << myVariable;
        return ss.str();
    }
   
   
    std::string GetName() const
    {
        return myVariableName;
    }

    std::string GetType() const
    {
        return myVariableType;
    }

    bool GetConst() const
    {
        return myConst;
    }
       
   
private:
    _Ty&        myVariable;

    std::string myVariableName;
    std::string myVariableType;

    bool        myConst;
};

////////////////////////////////////////////////////////////////

// This a handy helper class, when sometimes you need to create
// a variable and a reference to it. This actually fakes the
// reference and stores the variable in it self.
template< typename _Ty = std::string >
class CVarRefEmpty : public CVarRefBase
{
public:
    CVarRefEmpty( const std::string& varname, bool isconst = false ) :
      myVariable(),
      myVariableName( varname ),
      myVariableType( typeid( _Ty ).name() ),
      myConst( isconst )
    { }

    void        SetValue( const std::string& value )
    {
        if ( !myConst )
            std::cengstringstream( value ) >> myVariable;
    }
   
    std::string GetValue() const
    {
        std::stringstream ss;
        ss << myVariable;
        return ss.str();
    }
   
   
    std::string GetName() const
    {
        return myVariableName;
    }

    std::string GetType() const
    {
        return myVariableType;
    }

    bool GetConst() const
    {
        return myConst;
    }
       
   
private:
    _Ty         myVariable;

    std::string myVariableName;
    std::string myVariableType;

    bool        myConst;

};

////////////////////////////////////////////////////////////////

// This another helper class used when you encounter a const
// class
template< typename _Ty >
class CVarRefConst : public CVarRefBase
{
public:

   
    CVarRefConst( const std::string& varname, const _Ty& var )  :
      myVariable( var ),
      myVariableName( varname ),
      myVariableType( typeid( var ).name() ),
      myConst( true )
    {
         
    }


    void        SetValue( const std::string& value )
    {
       
    }
   
    std::string GetValue() const
    {
        std::stringstream ss;
        ss << myVariable;
        return ss.str();
    }
   
   
    std::string GetName() const
    {
        return myVariableName;
    }

    std::string GetType() const
    {
        return myVariableType;
    }

    bool GetConst() const
    {
        return myConst;
    }
       
   
private:
    const _Ty&  myVariable;

    std::string myVariableName;
    std::string myVariableType;

    bool        myConst;
};

////////////////////////////////////////////////////////////////

#endif
// end of cvarreference.h

// begin of canycontainer.h
#ifndef INC_CANYCONTAINER_H
#define INC_CANYCONTAINER_H

////////////////////////////////////////////////////////////////
//
// CAnyContainer.h
//
// Writen 30.01.2004
// by Petri Purho ( pete@markkupurho.fi )
//
// A basic container used with stl containers to make them type
// free containers. You don't have to worry about the template
// coding, you just declare a stl container with CAnyContainer
// type and you can push there variables of any type.
//
// example:
/*
    std::vector< CAnyContainer > myVector;
    myVector.push_back( 1 );    // integer
    myVector.push_back( std::string( "stringvalue" );
    myVector.push_back( 1.5 );  // double

    myVector[ 0 ] = std::string( "string" );

*/

// To get the values you can use CAnyContainerCast function
// or GetValue method. GetValue() returns the value as a string.
//
////////////////////////////////////////////////////////////////

#include <string>
#include <sstream>
#include <list>
#include <algorithm>

// #include "cvarreference.h"

////////////////////////////////////////////////////////////////

// This here is a basic set of containers, which stores
// variables of any type.

class CContainerBase
{
public:
    CContainerBase() { }
    virtual ~CContainerBase() { }
};

////////////////////////////////////////////////////////////////

template< class _Ty >
class CContainer : public CContainerBase
{
public:
    CContainer( const _Ty& ref ) : myVar( ref ) { }
    ~CContainer() { }

    _Ty myVar;
};

////////////////////////////////////////////////////////////////

class CAnyContainer
{
public:
    CAnyContainer() : myContainer( NULL ), myReference( NULL ) {  AddBan( this ); }
   
    template < class _Ty >
    CAnyContainer( const _Ty& reference ) : myContainer( NULL ), myReference( NULL )
    {
        if ( IsBanned( this ) == false )
        {
            delete myContainer;
            delete myReference;
        } else
            RemoveBan( this );
       

        CContainer<_Ty>* tmp_ptr = new CContainer< _Ty >( reference );
        myReference = new CVarRefConst<_Ty>( "", tmp_ptr->myVar );
        myContainer = tmp_ptr;
   
    }
   
    template<>
    CAnyContainer( const CAnyContainer& other ) : myContainer( NULL ), myReference( NULL )
    {

        if ( IsBanned( this ) == false )
        {
            delete myContainer;
            delete myReference;
        } else RemoveBan( this );
       
   
        other.BanMe();

        myContainer = other.myContainer;
        myReference = other.myReference;
    }

    ~CAnyContainer()
    {
        if ( IsBanned( this ) == false )
        {
            delete myContainer;
            delete myReference;
        } else RemoveBan( this );
               
    }
   
    template< class _Ty >
    CAnyContainer& operator= ( const _Ty& reference )
    {
        if ( IsBanned( this ) == false )
        {
            delete myContainer;
            delete myReference;
        } else
            RemoveBan( this );
       

        CContainer<_Ty>* tmp_ptr = new CContainer< _Ty >( reference );
        myReference = new CVarRefConst<_Ty>( "", tmp_ptr->myVar );
        myContainer = tmp_ptr;
       
        return *this;
    }

    std::string GetValue() const
    {
        return myReference->GetValue();
    }
   
    template< class _Ty >
    std::string GetValue( _Ty& var ) const
    {
        std::cengstringstream( GetValue() ) >> var;

        return GetValue();
    }

private:
    void BanMe() const
    {
        AddBan( this );
    }

    void AddBan( const CAnyContainer* banme ) const
    {
        if ( IsBanned( banme ) ) return;
        myDeleteBanList.push_back( banme );
    }

    void RemoveBan( const CAnyContainer* banned )
    {
        if ( IsBanned( banned ) == false ) return;
        myDeleteBanList.remove( banned );

    }

    bool IsBanned( const CAnyContainer* ban ) const
    {
        std::list< const CAnyContainer* >::iterator i;
        i = std::find( myDeleteBanList.begin(), myDeleteBanList.end(), ban );
        return ( i != myDeleteBanList.end() );
    }



    CContainerBase* myContainer;
    CVarRefBase*    myReference;

    static std::list< const CAnyContainer* > myDeleteBanList;
};

std::list< const CAnyContainer* > CAnyContainer::myDeleteBanList;

////////////////////////////////////////////////////////////////

std::ostream& operator << ( std::ostream& os, CAnyContainer& container ) 
{
    os << container.GetValue();
    return os;
}

////////////////////////////////////////////////////////////////

template< class _Ty >
_Ty CAnyContainerCast( const CAnyContainer& container )
{
    _Ty tmp_var;
    container.GetValue( tmp_var );
    return tmp_var;
}

////////////////////////////////////////////////////////////////

#endif
// end of canycontainer.h

// begin of main.cpp

#include <iostream>
#include <vector>
#include <string>
// #include "canycontainer.h"

int main()
{
    // Ensin teet stl containerin joka käyttää CAnyContaineria
    // tyyliin:
    std::vector< CAnyContainer > myVector;

    // Sen jälkeen voit survoa minkä tahansa tyyppistä tavaraa
    // tuhon stl containeriin.

    myVector.push_back( 10 );
    myVector.push_back( 10.5 );
    myVector.push_back( std::string( "tekstiä" ) );

    // Tekstin kanssa, siis tarkemmin merkkijonojen kanssa
    // joutuu vähän kikkaamaan ja käyttämään std::stringiä
    // koska templatet eivät tykkää merkkijonoista, koska
    // char[20] on eri tyyppinen muuttuja kuin char[19].
    // Tämä aiheuttaa epämiellyttäviä ongelmia jotka pystyy
    // kiertämään käyttämällä std::stringiä.

    // Voit myös muuttaa näitä suoraan, tyyliin
    myVector[ 0 ] = std::string( "muutettiin tekstiksi" );

    std::cout << myVector[ 0 ] << std::endl; // tulostaa: muutettiin tekstiksi
    std::cout << myVector[ 1 ] << std::endl; // tulostaa: 10.5

    // muuttujien arvoja saa GetValue metodilla.
    // Joka defaulttina palauttaa muuttujan arvon std::string
    // tyyppisenä
    std::string string_muuttuja = myVector[ 0 ].GetValue();

    // Muun tyyppisiä muuttujia saat ulos joko, GetValue( muuttuja )
    // metodilla tai CAnyContainerCast<> funktiolla.
    double double_muuttuja;
   
    myVector[ 1 ].GetValue( double_muuttuja );
   
    std::cout << double_muuttuja << std::endl; // tulostaa: 10.5

   
    myVector[ 1 ] = 20.5;
   
    double_muuttuja = CAnyContainerCast< double >( myVector[ 1 ] );

    std::cout << double_muuttuja << std::endl; // tulostaa: 20.5

    return 0;
}

// end of main.cpp