On Friday, 20 February 2015 at 12:23:49 UTC, Vlad Levenfeld wrote:
Let me illustrate with an example:
struct AudioClip {
float[2][] samples;
uint sampling_rate;
this (string path) {load (path, samples);}
void play () {some_C_audio_lib_call (samples.ptr,
samples.length, sampling_rate);}
}
// we'll start with an audio clip with contiguous layout in
memory
auto ac = AudioClip ("90 minutes of screaming cats.flac");
// now we define two implementations of the same filter
auto ref declaw_filter1 (R)(R r) if (isContiguousRange!R) {
// pattern match to get the size of the sample
static if (is (ElementType!R == float[stride], uint
stride)) {}
// i know the gsl functions don't work like this, just bear
with me
gsl_fft (ptr, stride, r.length);
gsl_fgemm (/*pretend this is sensible*/);
gsl_fft_inverse (ptr, stride, r.length);
return r;
}
auto declaw_filter2 (uint n)(float[n][] slice) {
// like declaw_filter1 but without the contiguous stuff
}
// now, we can finish this one of two ways
// the easy way:
ac.declaw_filter1.play; // UFCS all day
// or, if we passed a T[] made from AudioClip or defined
AudioClip to be implicitly convertible to T[]:
AudioClip ac2;
ac2.samples = ac.declaw_filter2;
ac2.sampling_rate = ac.sampling_rate; // this could
desynchronize after the code is refactored, opening us up for
bugs
ac2.play;
You could have the best of both worlds this way:
R declaw_filter3(R)(R r)if(is(R:float[stride][],size_t stride))
and write
ac.declaw_filter3.play;