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;

Reply via email to