//
// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
//
// The contents of this file are covered under the licence agreement in the
// file "LICENCE" distributed with Cforall.
//
// tupleFunction.c --
//
// Author           : Rob Schluntz
// Created On       : Mon Dec 04 17:41:45 2017
// Last Modified By : Rob Schluntz
// Last Modified On : Mon Dec 04 17:45:07 2017
// Update Count     : 2
//

struct S {
  int i;
  // dynamically allocated member ensures ctor/dtors are called correctly on temporaries
  int * ptr;
};

// with clause on reference parameter
void ?{}(S & this, int n) with(this) {
  i = n;
  ptr = (int *)malloc(sizeof(int));
}

void ?{}(S & this) {
  this{ 0 };
}

void ?{}(S & this, S other) {
  this{ other.i };
}

S ?=?(S & this, S other) with(this) {
  i = other.i;
  *ptr = *other.ptr;
  return this;
}

void ^?{}(S & this) with(this) {
  free(ptr);
}

struct S2 {
  S s;
};

void ?{}(S2 & this, int n) {
  (this.s){ n };
}

forall(otype T)
struct Box {
  T x;
};

forall(otype T)
void ?{}(Box(T) & this) with(this) { // with clause in polymorphic function
  x{};
}

void print(int i) { printf("%d", i); }

forall(otype T | { void print(T); })
void foo(T t) {
  Box(T) b = { t };
  with(b) {  // with statement in polymorphic function
    print(x);
    printf("\n");
  }
}

// ensure with-statement temporary generation works correctly
S mk() {
  printf("called mk\n");
  return (S) { 444 };
}

// ensure with-statement temporary generation with reference-returning functions works correctly
S & ref() {
  static S var = { 123456789 };
  return var;
}

int main() {
  S2 s2 = { 12345 };
  with (s2) {
    with(s) { // with s2.s
      printf("%d %d %d\n", i, s.i, s2.s.i);
      foo(i);  // s.i
      with(mk()) {
        printf("%d %d %d\n", i, i, i);
        with(ref()) {
          printf("%d %d %d\n", i, i, i);
        } // with ref()
        with(ref()) {
          printf("%d %d %d\n", i, i, i);
        } // with ref()
      } // with mk()
    } // with s
  } // with s2
}

// Local Variables: //
// tab-width: 4 //
// End: //
