This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  anything Data Type
  Submitted by



An anything as I understand it, is a generic or variant data type. This is therefore what I've written. It's a class that can contain any other datatype, and switch at runtime. The main.cpp contains some examples/tests, and the anything.h is the datatype itself. A simple example of how to use it would be.

anything any="hello";

cout << any.as<string() << endl; any = 10; int test = any;

etc.



What an anything does if it encounters different type requests then it contains depends on the traits it's compiled with, thus far i've thought about silent replacment, assert casts, and exception casts. The anything can also be found on my website www.codeweld.com where you can find contact information too.


Currently browsing [anything.zip] (3,647 bytes) - [anything.h] - (9,889 bytes)

/*/////////////////////////////////////////////////////////////////////
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

Currently browsing [anything.zip] (3,647 bytes) - [main.cpp] - (1,664 bytes)

#include <iostream>
#include <string>
#include <list>
#include "anything.h"

using namespace std; using nAnything::anything; // teststruct to demonstrate the true generality of anythings struct teststruct { teststruct(){}; teststruct( string as ):s(as){} // two operators are required in order for anythings to work with the data bool operator==( const teststruct& b ){ return s==b.s; } bool operator<( const teststruct& b ){ return s<b.s; } string s; }; // demonstrating anything as argument without exceptions void testfunc2( anything any ) { string value; if( any.get( value ) ) { cout << value << endl; } else { cout << "invalid argument for testfunc" << endl; } }

void main() { // argument test without exceptions anything any2 = "test"; testfunc2( any2 ); // tree test anything tree1; // build the tree with arbitary data tree1[teststruct("blub")] = "blublub"; tree1["test"] = teststruct(); tree1[teststruct("test")][10] = 20; tree1["20"]["40"] = list<int>( 5, 10 ); // proove it working cout << tree1[teststruct("test")][10].as<int>() << endl; // copy test anything tree2=tree1.clone(); // equality test; cout << "tree1 and tree2 are equal:" << (tree1==tree2) << endl; // make a difference in the tree tree1[teststruct("blub")] = 104.4; // proove the difference cout << "tree1 and tree2 are equal:" << (tree1==tree2) << endl; // test the assigned tree values cout << tree2[teststruct("blub")].as<string>() << endl;

// a graph :) nice anything one, two; one["test"]="test"; one["test2"]["test"]=one["test"]; one["test"]="test2"; cout << one["test2"]["test"].as<string>() << endl; }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.