Re: Non-container Iterators
On Jul 24, 11:18 pm, "Leslie Sanford" <jabberdab...@bitemehotmail.com>
wrote:
"Daniel T." wrote:
"Leslie Sanford" wrote:
My area of programming is DSP. I write things like filters, oscillator=
s,
envelopes, etc. I've been looking at STL iterators, and what's struck =
me
is that if I can find ways to model my code using STL's iterator
conventions, I could possibly make my code more economic while
probably losing little to no efficiency.
Then you might find this interesting:
class fibonacci: public std::iterator< std::forward_iterator_tag, int >
<snip>
Yes, indeed. That is very interesting.
<snip>
I need to keep track of the phase. The phase is state that needs to
persist across iterations. This means that I need to give the iterator=
a
pointer to the phase variable when I create it so that as it's iterati=
ng,
it's also modifying the phase variable. Something like:
// Inside my Oscillator class somewhere:
it = PhaseIterator it(&phase, increment);
// Inside the PhaseIterator class:
PhaseIterator &operator++()
{
*phase += increment;
if(phase >= 1.0f)
{
phase -= 1.0f;
}
return *this;
}
This works, but it means that I can only use one phase iterator at a
time.
Not if you put 'phase' inside the iterator. Then you can give two
iterators the same phase and increment and advance each of them a
different amount, and they will each be at a different spot in the
"container".
Understood.
The key is to provide a sentinel iterator. In your case, the sentinel
can be a PhaseIterator that has an increment of 0.
In this case, there is no sentinel iterator as an oscillator, which a pha=
se
accumulator drives, can cycle indefinitely, a kind of circular buffer, I
suppose.
Is it acceptable for an iterator to never reach an "end"? I would have
another way for testing for the end of the loop, specifically the end of =
the
buffer that I'm filling. I should be able to increment the phase iterator
indefinitely.
while(first != last)
{
*first = *phase;
phase++;
first++;
}
Since (triple) posting, I've been giving this approach some thought, and =
I
was wondering if a Generator would be a more appropriate model than an
Iterator to represent a phase accumulator.
http://www.sgi.com/tech/stl/Generator.html
class PhaseAccumulator
{
public:
typedef float result_type;
private:
float phase;
float increment;
public:
PhaseAccumulator(float phase, float increment)
{
this->phase = phase;
this->increment = increment;
}
result_type operator()()
{
phase += increment;
if(phase >= 1.0f)
{
phase -= 1.0f;
}
return phase;
}
};
I can have a Square waveform represented as a unary function:
typedef std::unary_function<float, float> WaveShapeBase;
struct Square : public WaveShapeBase
{
result_type operator()(argument_type phase) const
{
assert(phase >= 0.0f && phase < 1.0f);
return phase < 0.5f ? -1.0f : 1.0f;
}
};
And use both in a loop to fill a buffer:
class Oscillator
{
PhaseAccumulator phase;
Square wave;
public:
// Stuff...
void Process(float *first, float *last)
{
while(first != last)
{
*first = wave(phase());
first++;
}
}
}
Maybe this is a more appropriate approach given the concepts involved?
That sounds like it would work. Then your process function can be
replaced by the generate algorithm.
float arr[20];
generate( arr, arr + 20, PhaseAccumulator(0, 0.3) );
or better:
vector< float > arr;
generate_n( back_inserter( arr ), 20, PhaseAccumulator(0, 0.3) );
But if you make a powerful enough PhaseAccumulator iterator, you won't
*need* to fill the array with values, you can use the iterator
directly over the calculated container.