/*/////////////////////////////////////////////////////////////////////
License....: LGPL 2.1 - http://www.gnu.org/copyleft/lesser.html
http://www.opensource.org/licenses/lgpl-license.php
Name.......: anything 0.1
Description: A generic or variant ( as opposed to templated ) data type.
A anyimpl<castTrait> is a type that can hold any other type including itself.
It is optimized for two special cases, one beeing char arrays that
form string iterals in C++ that are beeing interpreted as std::strings
and the other beeing map<anyimpl<castTrait>,anyimpl<castTrait>>, for which the [] operator
is supported from the anyimpl<castTrait>.
Copyright (C) 2003 Florian Bösch, http://www.codeweld.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
////////////////////////////////////////////////////////////////////////
Sucessfull Compilerlist for version 0.1.1:
-gcc version 2.95.3 20010315 (release)
-gcc version 2.95.3-5 (cygwin special)
-Microsoft (R) 32-Bit C/C++-Standardcompiler Version 13.00.9466 für 80x86
( with one expetions, templated casts don't work )
Caveats:
-Beware that anythings use references internaly unless you clone one explicitly
-No testing whatsoever has been made for threaded envoirments
-There are surely many cases where using anythings isn't apropriate
I consider the advantages/disadvantages as the following
+flexibilty
+type testing
-speed
-safety
-type mismatches produced with as<type>() are resolved depending on the cast traits of the anyimpl.
-anythings are very strict and non converting
Latest fixes:
-Fixed an internal reference copy issue ( one instance too many )
///////////////////////////////////////////////////////////////////////*/
#ifndef ANYTHING_H
#define ANYTHING_H
#include <map>
#include <string>
#include <vector>
#include <assert.h>
#include <exception>
#include <typeinfo>
namespace nAnything
{
using namespace std;
template <class _T> class shared_ptr
{
public:
shared_ptr():_valPtr(new _value()){}
shared_ptr( _T* t ):_valPtr( new _value(t) ){}
shared_ptr( const shared_ptr<_T>& sPtr ):_valPtr(sPtr.ref()){}
~shared_ptr(){ unref(); }
_T& operator*() const { return (*_valPtr->get()); }
_T* operator->() const { return _valPtr->get(); }
shared_ptr<_T>& operator=( _T* t ){ unref(); _valPtr = new _value(t); return *this; }
shared_ptr<_T>& operator=( const shared_ptr<_T>& b ){ unref(); _valPtr=b.ref(); return *this;}
_T* ptr() const { if( _valPtr )return _valPtr->get(); return 0; }
private:
class _value
{
public:
_value():references(1),__dataPtr(0){}
_value( _T* t ):references(1),__dataPtr(t){}
~_value(){ delete __dataPtr; }
_T* get()
{
if( __dataPtr )
return __dataPtr;
return (__dataPtr = new _T());
}
_value* ref(){ ++references; return this; }
int unref(){ return --references; }
private:
int references;
_T* __dataPtr;
};
void unref(){ if( _valPtr && !_valPtr->unref() ) delete _valPtr; }
_value* ref() const { if( _valPtr ) return _valPtr->ref(); return 0; }
_value* _valPtr;
};
template <class _T>
class anytype;
template <class castTrait>
class anyimpl;
class anyinter
{
public:
virtual anyinter* clone() const{ return new anyinter; }
virtual int type() const { return 0; }
virtual anyinter& operator=( const anyinter& b ){ return *this; }
virtual ~anyinter(){}
virtual bool operator==( const anyinter& b ){ return true; }
virtual bool operator<( const anyinter& b ){ return true; }
};
template <class _T>
class anytype: public anyinter
{
typedef anytype<_T> _myType;
public:
anytype():data(_T()){}
anytype( const _T& d ):data(d){}
virtual anyinter* clone() const{ return new anytype<_T>( data ); }
virtual int type() const{ return _myType::id; }
virtual bool operator==( const anyinter& b )
{
return data==reinterpret_cast<const _myType&>(b).data;
}
virtual bool operator<( const anyinter& b )
{
return data < reinterpret_cast<const _myType&>(b).data;
}
virtual anyinter& operator=( const anyinter& b )
{
data = reinterpret_cast<const _myType&>(b).data;
return *this;
}
_T data;
static const int id;
};
template <class _T>
const int anytype<_T>::id = reinterpret_cast<const int>(&anytype<_T>::id);
struct replace_cast_traits
{
template <class T>
T& as( shared_ptr<anyinter>& any )
{
if( any.ptr() )
{
if( any->type() != anytype<T>::id )
{
any = new anytype<T>();
}
}
else
{
any = new anytype<T>();
}
return reinterpret_cast<anytype<T>*>(any.ptr())->data;
}
template <class T>
T& as( shared_ptr<anyinter>& any, const T& arg )
{
if( any.ptr() )
{
if( any->type() != anytype<T>::id )
{
any = new anytype<T>(arg);
}
}
else
{
any = new anytype<T>(arg);
}
return reinterpret_cast<anytype<T>*>(any.ptr())->data;
}
};
/* // what's the compiler switch to turn gcc exeptions on???
struct any_bad_cast
{
};
struct throw_cast_traits
{
template <class T>
T& as( shared_ptr<anyinter>& any )
{
if( any.ptr() )
{
if( any->type() != anytype<T>::id )
{
throw( any_bad_cast() );
}
}
else
{
any = new anytype<T>();
}
return reinterpret_cast<anytype<T>*>(any.ptr())->data;
}
template <class T>
T& as( shared_ptr<anyinter>& any, const T& arg )
{
if( any.ptr() )
{
if( any->type() != anytype<T>::id )
{
throw( any_bad_cast() );
}
}
else
{
any = new anytype<T>(arg);
}
return reinterpret_cast<anytype<T>*>(any.ptr())->data;
}
};
*/
struct assert_cast_traits
{
template <class T>
T& as( shared_ptr<anyinter>& any )
{
if( any.ptr() )
{
if( any->type() != anytype<T>::id )
{
assert(0);
}
}
else
{
any = new anytype<T>();
}
return reinterpret_cast<anytype<T>*>(any.ptr())->data;
}
template <class T>
T& as( shared_ptr<anyinter>& any, const T& arg )
{
if( any.ptr() )
{
if( any->type() != anytype<T>::id )
{
assert(0);
}
}
else
{
any = new anytype<T>(arg);
}
return reinterpret_cast<anytype<T>*>(any.ptr())->data;
}
};
template <class castTrait>
class anyimpl
{
typedef map<anyimpl<castTrait>,anyimpl<castTrait> > anymap;
typedef vector<anyimpl<castTrait> > anyvec;
public:
anyimpl(){}
anyimpl( const anyimpl<castTrait>& b ):any(b.any){}
template <class T>
anyimpl( const T& arg ):any( new anytype<T>(arg) ){}
anyimpl( const char* arg):any( new anytype<string>(arg) ){}
anyimpl( anyinter* a ):any(a){}
anyimpl<castTrait>& operator=( anyimpl<castTrait> arg )
{
if( type() == arg.type() )
*any=*arg.any;
else
any = arg.any;
return *this;
}
// doesn't work on M$C
template <class T>
operator T(){ return as<T>(); }
template <class T>
T& as( const T& arg )
{
return cast.as<T>(any,arg);
}
template <class T>
T& as()
{
return cast.as<T>( any );
}
template <class T>
bool get( T& t )
{
if( is<T>() )
{
t = as<T>();
return true;
}
return false;
}
template <class T>
T* get()
{
if( is<T>() )
{
return &as<T>();
}
return 0;
}
anyimpl<castTrait>& operator[]( anyimpl<castTrait> i )
{
return as<anymap>()[i];
}
int type() const { if( any.ptr() ) return any->type(); return 0; }
template <class T>
bool is() const
{
if( any.ptr() )
return anytype<T>::id == any->type();
return false;
}
anyimpl<castTrait> clone(){ return anyimpl<castTrait>( any->clone() ); }
bool operator<( const anyimpl<castTrait>& b ) const
{
if( !any.ptr() && b.any.ptr() ) return true;
if( any.ptr() && !b.any.ptr() ) return false;
if( !any.ptr() || !b.any.ptr() ) return false;
if( any->type() != b.any->type() ) return any->type() < b.any->type();
return *any<*b.any;
}
bool operator==( const anyimpl<castTrait>& b ) const
{
if( !any.ptr() && !b.any.ptr() )return true;
if( !any.ptr() || !b.any.ptr() ) return false;
if( any->type() != b.any->type() ) return false;
return *any==*b.any;
}
protected:
shared_ptr<anyinter> any;
castTrait cast;
};
template <class castTrait>
bool operator==( const anyimpl<castTrait>& a, const anyimpl<castTrait>& b )
{
return a.operator==(b);
}
template <class castTrait>
bool operator!=( const anyimpl<castTrait>& a, const anyimpl<castTrait>& b )
{
return !(a.operator==(b));
}
template <class castTrait>
bool operator<( const anyimpl<castTrait>& a, const anyimpl<castTrait>& b )
{
return a.operator<(b);
}
template <class _T>
class anyis
{
public:
template <class castTrait>
bool operator()( const anyimpl<castTrait>& a )
{
return a.type() == anytype<_T>::id;
}
};
template <class _T>
class anyisnot
{
public:
template <class castTrait>
bool operator()( const anyimpl<castTrait>& a )
{
return a.type() != anytype<_T>::id;
}
};
typedef anyimpl<replace_cast_traits> anything;
// typedef anyimpl<throw_cast_traits> throwany; // what's the compiler switch to turn gcc exeptions on???
typedef anyimpl<assert_cast_traits> assertany;
}//nAnything
#endif // ANYTHING_H |