And now I remember that people still use the stupid default of 8 spaces per tab, and I can't specify to use 2 in the text.

mixin template Batch(alias transaction, alias operation, size_t max = 0x10) {
  import std.typecons: Tuple, tuple;
  import std.traits: Parameters,ReturnType;
  import std.array: Appender;

  static assert(is(ReturnType!operation == void));
  alias Item = Tuple!(Parameters!operation);
  Appender!(Item[]) cache;
  void opCall(Parameters!operation args) {
    cache.put(tuple(args));
    if(cache.data.length > max)
      flush();
  }
  void flush() {
    if(cache.data.length == 0) return;
    scope(exit) cache.shrinkTo(0);
    transaction({
        foreach(ref args; cache.data) {
          operation(args.expand);
        }
      });
  }
  void completely(Handle)(Handle handle) {
    scope(exit) flush();
    handle();
  }
}

mixin template Batch(alias setup, alias operation, alias takedown, size_t max = 0x10) {
  void transaction(Callable)(Callable inside) {
    setup();
    scope(exit) takedown();
    inside();
  }
  mixin Batch!(transaction,operation,max);
}


unittest {
  import print: print;
  struct Foo {
    void batchable_operation(int a, int b) {
      print("operate on",a,b);
    }
    void setup() {
      print("setup for flushing");
    }
    void commit() {
      print("commit");
    }
    void opCall(int a, int b) {
      print("oops",a,b);
    }
    mixin Batch!(setup,
                 batchable_operation,
                 commit,
                 0x10) C;
  }

  Foo foo;

  foo.completely({
      for(int i=0;i<20;++i) {
        foo.C(i,i*2);
// .C isn't needed... except when the struct implements the
        // same operation, in which case that's the default!
        foo(i,i*3);
        print("did we do it?",i);
      }
    });
  print("done");

  struct Bar {
    void transaction(Callable)(Callable inside) {
      print("beginning");
      scope(exit) print("ending");
      inside();
    }
    void batchable_operation(int a, int b) {
      print("bar on",a,b);
    }
    mixin Batch!(transaction,
                 batchable_operation) C;
  }

  Bar bar;
  bar.completely({
      for(int i=0;i<20;++i) {
        bar(i,i*2);
      }
    });
}

Reply via email to