Boost logo

Boost Users :

From: Istvan Buki (buki.istvan_at_[hidden])
Date: 2008-07-21 13:08:15


On Mon, Jul 21, 2008 at 5:02 PM, Zeljko Vrba <zvrba_at_[hidden]> wrote:

> On Mon, Jul 21, 2008 at 03:27:39PM +0200, Istvan Buki wrote:
> >
> > InMetaData contain, among other things, the type of the input data. More
> > specifically, InMetaData::type is a fusion map describing all the fields
> of
> > the input data.
> >
> Given that you're using a map, I guess that the user has to define "dummy"
> types as field names (unless he's satisfied with exactly one value for each
> primitive type)?
>

Yes, Indeed. But they are not as dummy as one could first think, I use them
to store the database field name in case I use one. For example:

  struct id
  {
    typedef fields::id type ;
    typedef int value_type ;
    static std::string value_name( void ) { return "id" ; } // return the
database field name
  } ;

> >
> > typename result_of::join< InMetaData, CacheMetaData, IndexType
> > >::type
> > apply( const typename InMetaData::type &r )
> > {
> > typename IndexType::value_type key_value =
> > fusion::at_key< IndexType >( r ) ;
> > return fusion::as_map( fusion::join( r, fusion::erase_key< IndexType
> >(
> > cache_.lookup( key_value ) ) ) ) ;
> > }
> >
> Given your explanation, I have several questions about this code:
>
> - the name apply -- is this function a part of some larger class, so the
> name
> is prescribed by some protocol?
>

Yes, the join component derives from a class whose responsibility is to
manage input and output connections. In the base class I do:

  void exec( void )
  {
    output_connection_->value() =
      static_cast< FuncType *>( this )->apply( input_connection_.value() ) ;
  }

>
> - You have CacheMetaData as template parameter, yet you do not use it --
> you
> have an instance variable cache_ instead. Is this just for illustration
> purposes or some other reason?

It is used to create the cache_ object which is a reference to a cache
object .
Here is the code of the join class that shows more clearly how it works:

  template < typename InMetaData, typename CacheMetaData, typename IndexType
>
  struct join
  {
    typedef typename data_cache< CacheMetaData, IndexType >::impl join_cache
;

    struct impl : public one2one_component< InMetaData, result_of::join<
InMetaData, CacheMetaData, IndexType >, impl >
    {
      impl( join_cache &c ) : cache_( c ) { }

      typename result_of::join< InMetaData, CacheMetaData, IndexType >::type
      apply( const typename InMetaData::type &r )
      {
    typename IndexType::value_type key_value =
      fusion::at_key< IndexType >( r ) ;
    return fusion::as_map( fusion::join( r, fusion::erase_key< IndexType >(
cache_.lookup( key_value ) ) ) ) ;
      }

    private:
      join_cache &cache_ ;
    } ;
  } ;

>
> - the return statement prejudices "map" as implementation, i.e., the code
> does not look generic enough :-) is there some metafunction that could
> replace fusion::as_map with something more generic, in case the user would
> like to use e.g. vectors? ditto for erase_key?

I did not think about it. Currently my design is to pass map only between
components.
However, I use some transformation between map and vector in the database
component (see beginning of this thread for more detail). This can perhaps
be used as the starting point to achieve exactly that.

[...]

>
> Could you please also write a simple example of composition of two
> elements?

> (I.e. how it would be used by the 'end-user' programmer?)
>

Here is a small example that read data from a CSV file, filter out a column
and write the result to another CSV file.

 namespace fields
{
  struct first_name
  { typedef fields::first_name type ; typedef std::string value_type ; } ;
  struct last_name
  { typedef fields::last_name type ; typedef std::string value_type ; } ;
  struct age
  { typedef fields::age type ; typedef int value_type ; } ;
  struct address
  { typedef fields::address type ; typedef std::string value_type ; } ;
  struct postal_code
  { typedef fields::postal_code type ; typedef std::string value_type ; } ;
}

struct AddressBook
{
  typedef fusion::map <
    fusion::pair< fields::first_name::type, fields::first_name::value_type
>,
    fusion::pair< fields::last_name::type, fields::last_name::value_type >,
    fusion::pair< fields::age::type, fields::age::value_type >,
    fusion::pair< fields::address::type, fields::address::value_type >,
    fusion::pair< fields::postal_code::type, fields::postal_code::value_type
>
> type ;
} ;

int
main()
{
  metl::csv_istream< AddressBook >::impl in_file( "addrbook.csv" ) ;

  typedef metl::filter< AddressBook, fields::age >::impl filter_t ; //
remove the 'age' column
  typedef metl::result_of::filter< AddressBook, fields::age >
filter_result_t ;

  filter_t my_filter ;

  metl::csv_ostream< filter_result_t >::impl out_file( "out.csv" ) ;

  // connect the components.
  in_file.output( my_filter.input() ) ;
  my_filter.output( out_file.input() ) ;

  while ( in_file.good() )
    {
      in_file.exec() ;
      my_filter.exec() ;
      out_file.exec() ;
    }

  return 0 ;



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net