Boost logo

Boost Users :

From: Zeljko Vrba (zvrba_at_[hidden])
Date: 2005-07-06 01:11:10


OK, here it is without leading ~s. It seems GPG inserts them for some
strange reason when there is leading space on the line.

David Abrahams wrote:
|
| I don't understand yet. What is the difference between stage_1 and
| stage_2? Fewer arguments in stage_1?
|
exactly.

e.g. stage reading from file:

template<typename Result>
struct file_reader {
   typedef Result result_type;
   istream f_;

   const std::pair<Result, bool> &operator()() {
     static std::pair<Result, bool> r;
     f_.read(&r.first, sizeof(Result));
     r.second = f_;
     return r;
   }

   // some initialization stuff to set f_

};

stage calculating unary function on its input (and input is, of course,
a stage):

template<typename Result, typename F1, typename Input1>
struct unary_op {
   typedef Result result_type;
   F1 f_;
   Input1 input1_;

   const std::pair<Result, bool> &operator() {
     static std::pair<Result, bool> r;
     typename Input1::result_type const &i1 = input1_();
     r.first = f_(i1.first);
     r.second = i1.second;
     return r;
   }

   // some initialization to set input1_ and f_
};

stage adding its two inputs:

template<typename Result, typename F2, typename Input1, typename Input2>
struct binary_op {
   typedef Result result_type;
   F2 f_;
   Input1 input1_;
   Input2 input2_;

   const std::pair<Result, bool> &operator() {
     static std::pair<Result, bool> r;
     typename Input1::result_type const &i1 = input1_();
     typename Input2::result_type const &i2 = input2_();
     r.first = f_(i1.first, i2.first);
     r.second = i1.second && i2.second;
     return r;
   }

   // init to set i1_ and i2_
};

this would be the intended usage:

//
// reading input from 2 files, producing as result x + sqrt(y)
//
file_reader<double> f1(file1);
file_reader<double> f2(file2);
unary_op<double, ..fill in..> sqrt_stage(f2, sqrt);
binary_op<double, ..fill in..> add_stage(f1, sqrt_stage,
   plus<double, double>());

// this loop would be another "stage" parametrized by the function
// performing the actual work done in the body.
while(1) {
   typename adder::result_type r = ad();
   if(!r.second) break;
   // do something with the data
}

ultimately, would it be possible to write somehting like:

file_reader<some_struct> f1(file1);
file_reader<another_struct> f2(file2);
// note the difference in structs! stages can convert types between
// input and output

//
// do some template magic :)
//

stage_op(
   my_consumer_functor(), // obvious
   stage_op( // producer for the consumer
     plus<double, double>(), // operation to perform on two inputs
     f1, // provider for the first argument
     stage_op(
       sqrt<double>(), // function for this stage
       f2))) // provider for this stage

If the outer stage_op(my_consumer_functor()..) is removed then I get a
'stream' from which I can extract individual element by calling
operator() repeatedly.

Please view this final use case as the thing I'm really trying to
achieve. The example stage implementations might be on the totally wrong
track.

Something along current container/iterator[1]/algorithm/functor
framework (no, I can't read the whole data set into memory :)), but
which would work in a 'lazy' manner producing values on demand only. I
believe this is called 'lazy evaluation' in some functional languages.
Also I need to be able to define alternate stopping criterion (e.g. stop
when ALL streams are exhausted, not the first one - this is useful for
merging several streams into a single stream).

[1] maybe just define new iterator classes?

In the meantime I've read the Phoenix documentation and it seems I could
achieve this with Phoenix. I might be mistaken. Tonight I'm writing my
first prototype code. I'm open to all suggestions.

Thanks in advance for all suggestions.


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