Boost logo

Boost :

From: Dylan Cuthbert (dylan_at_[hidden])
Date: 2002-09-08 21:11:41


You could use partial specialization ala MPL/Loki to switch between using
your type-specific efficient code and a generic any implementation.

Here's something I knocked up a few months ago to hide driver/platform
dependent data but still allow the data to be passed around "higher up" in
the interface.

The union "simple_type" contains the supported types - should probably use
"variant" so complex types (with constructors) can be held - either Andrei's
version or the boost version. Anyway, the code shows how you can switch the
internal representation depending on its type.

This uses the Loki type manipulator classes:

#include <loki/TypeManip.h>
#include <loki/Typelist.h>
#include <boost/any.hpp>

namspace impl
{

/*---------------------------------------------------*/
/*! blind Data encapsulation for platform specific
 * drivers
 *
 * \author Dylan Cuthbert
 * \date 2002/04/30
*//*-------------------------------------------------*/

class Data
{

public:
 struct twoshorts_t
 {
  short value[2];
 };

 struct fourchars_t
 {
  char value[4];
 };

 typedef int int_t;
 typedef unsigned int uint_t;
 typedef float float_t;

private:

 typedef boost::any complex_type;

 union simple_type
 {
  int_t _value_i;
  uint_t _value_ui;
  float_t _value_f;
  twoshorts_t _value_2s;
  fourchars_t _value_4c;

//! overloaded functions for returning of data types

  float_t& getImplData( Loki::Type2Type< float_t > ) { return
_value_f; }
  int_t& getImplData( Loki::Type2Type< int_t > ) { return
_value_i; }
  uint_t& getImplData( Loki::Type2Type< uint_t > ) { return
_value_ui; }
  twoshorts_t& getImplData( Loki::Type2Type< twoshorts_t > ) { return
_value_2s; }
  fourchars_t& getImplData( Loki::Type2Type< fourchars_t > ) { return
_value_4c; }

//! const overloaded functions for returning of data types

  const float_t& getImplData( Loki::Type2Type< float_t > ) const
{ return _value_f; }
  const int_t& getImplData( Loki::Type2Type< int_t > ) const
{ return _value_i; }
  const uint_t& getImplData( Loki::Type2Type< uint_t > ) const
{ return _value_ui; }
  const twoshorts_t& getImplData( Loki::Type2Type< twoshorts_t > ) const
{ return _value_2s; }
  const fourchars_t& getImplData( Loki::Type2Type< fourchars_t > ) const
{ return _value_4c; }

  simple_type() : _value_ui( 0 ) { }
 };

//! the actual data

 simple_type _simple;
 complex_type _complex; // if complex data is needed it is stored here

 template< class T >
 class Access
 {
 public:

  static const bool COMPLEX = ( Loki::TL::IndexOf< TYPELIST_5( int_t,
uint_t, float_t, twoshorts_t, fourchars_t ), T >::value == -1 );

  struct Complex
  {
  private:
   static inline void force_set( Data& _D )
   {
    _D._complex = T();
   }

   static inline bool check_empty( Data& _D )
   {
    return ( _D._complex.empty() || _D._complex.type() != typeid( T ) );
   }

  public:
   static T& GetImplData( Data& _D )
   {

    if ( check_empty( _D ) ) force_set( _D );

    return *boost::any_cast< T >( &_D._complex );
   }

   static const T& GetImplData_const( const Data& _D )
   {
    if ( check_empty( _D ) ) return T();

    return *boost::any_cast< const T >( &_D );
   }

   static void SetImplData( Data& _D, const T& _Value )
   {
    _D._complex = _Value;
   }
  };

  struct Simple
  {
   static T& GetImplData( Data& _D )
   {
    return _D._simple.getImplData( typename Loki::Type2Type< T >() );
   }

   static const T& GetImplData_const( const Data& _D )
   {
    return _D._simple.getImplData( typename Loki::Type2Type< T >() );
   }

   static void SetImplData( Data& _D, const T& _Data )
   {
    _D._simple.getImplData( typename Loki::Type2Type< T >() ) = _Data;
   }
  };

  typedef typename Loki::Select< COMPLEX, Complex, Simple >::Result
Interface;

 };

public:
 Data() { }

 template< class D >
 Data( const D& _Data )
 {
  typename Access<D>::Interface::SetImplData( *this, _Data );
 }

//! allow most forms of access

 template< class D >
 D& implData() // ????
 {
  return Access<D>::Interface::GetImplData( *this );
 }

//! allow most forms of access

 template< class D >
 const D implData() const
 {
  return Access<D>::Interface::GetImplData_const( *this );
 }
};

} // end namespace impl

--
---------------------------------
Q-Games, Dylan Cuthbert.
http://www.q-games.com
P2P internet radio - http://www.peercast.org
"Geoff Leyland" <geoff.leyland_at_[hidden]> wrote in message
news:1B405A46-C18E-11D6-B7E6-003065F9F514_at_epfl.ch...
> On Vendredi, septembre 6, 2002, at 01:21 , "Dylan Cuthbert"
> <dylan_at_[hidden]> wrote:
>
> > Looks like you've had a good play with it, I presume it supports any
> > types
> > now rather than the limited set you had before?
>
> Uh, no. :-(  I've been waiting for boost 1.29 for a "new" any, and
> following dynamic_any, which fixes one of the problems you mentioned
> earlier.  And, basically, I've been lazy.  I've got quite a bit of code
> that uses the .be<> or .ref<> syntax, and I thought I'd wait to see what
> happened with any_cast<> and extract<> before I made the changes.  Of
> course, ideally, the contained type will be parameterised - but there'd
> have to be matching syntax for the contained type from the object
> returned by a
>
> wc_ptr ptr = a["one.two.three.four"];
>
> ptr contains a pointer to a and the parsed path, but won't do anything
> until you "use" it.  This means that if a["one.two.three.four"] doesn't
> exist, then
>
> ptr.be<int>(); will throw
> ptr.exists(); will return false
> and
> ptr = 4.0; will build any necessary parts of the path in a (hopefully)
> exception safe manner, ie, a won't be changed until we've build the
> contained type and any intermediate containers, and if any building
> fails, no memory will be leaked (hopefully).
>
> So if your contained type doesn't use be<>, but extract<>, you'd
> probably want wc_ptr to have an extract rather than a be.
>
> There's a .guess() partly implemented, which contains those horrible
>
> template <class T> operator T() 's
>
> which might be an acceptable way of doing things - I really prefer
>
> std::map<std::string, vertex<real, vertex_less> >::size_type s =
> a["the.map.size"].guess();
>
> to
>
> std::map<string, vertex<std::real, vertex_less> >::size_type s =
> a["the.map.size"].be<std::map<std::string, vertex<real, vertex_less>
>  >::size_type>
>
> (which is obviously a bit of a contrived example, but I get real ones
> every day).
>
> anyway, have a look, and see what you think.  It's definitely
> (obviously?) a work in progress so any feedback (from anyone) would be
> cool.
>
> cheers,
> goof
>
> --
> The early bird catches the worm.
> If you want something else for breakfast, get up later.
>
> Geoff Leyland, Village Idiot
> Laboratoire d'energetique industrielle
> LENI-DGM-EPFL, CH-1015, Lausanne, Switzerland
> Phone: +41 (21) 693 3505, Fax: +41 (21) 693 35 02
>
> _______________________________________________
> Unsubscribe & other changes:
http://lists.boost.org/mailman/listinfo.cgi/boost
>

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk