// examples/gc_stack_roots translated by mycpp

// BEGIN mycpp output

#include "mycpp/runtime.h"

GLOBAL_STR(str0, "no");
GLOBAL_STR(str1, "collect");
GLOBAL_STR(str2, "foo");
GLOBAL_STR(str3, "bar");
GLOBAL_STR(str4, "bing");
GLOBAL_STR(str5, "bong");
GLOBAL_STR(str6, "indirect");
GLOBAL_STR(str7, "collect");
GLOBAL_STR(str8, "OK");
GLOBAL_STR(str9, "not");
GLOBAL_STR(str10, "swept");
GLOBAL_STR(str11, "foo");
GLOBAL_STR(str12, "bar");
GLOBAL_STR(str13, "context");
GLOBAL_STR(str14, "member");
GLOBAL_STR(str15, "watch");
GLOBAL_STR(str16, "out");
GLOBAL_STR(str17, "%s");
GLOBAL_STR(str18, "foo");
GLOBAL_STR(str19, "bar");

namespace gc_stack_roots {  // forward declare

  class ctx_Stasher;

}  // forward declare namespace gc_stack_roots

namespace gc_stack_roots {  // declare

void print_list(List<BigStr*>* l);
void calls_collect();
void ignore_and_collect(List<BigStr*>* l);
List<BigStr*>* collect_and_return(List<BigStr*>* l);
BigStr* collect_and_slice(BigStr* s);
class ctx_Stasher {
 public:
  ctx_Stasher(List<BigStr*>* l);
  ~ctx_Stasher();
  List<BigStr*>* l;

  DISALLOW_COPY_AND_ASSIGN(ctx_Stasher)
};

void no_collect();
void simple_collect();
void indirect_collect();
void arg_roots();
void alias();
void collect_scoped_resource();
void collect_in_loop();
void collect_in_comprehension();
void run_tests();
void run_benchmarks();

}  // declare namespace gc_stack_roots

namespace gc_stack_roots {  // define


void print_list(List<BigStr*>* l) {
  StackRoot _root0(&l);

  for (ListIter<BigStr*> it(l); !it.Done(); it.Next()) {
    BigStr* s = it.Value();
    StackRoot _for(&s  );
    print(s);
  }
}

void calls_collect() {
  mylib::MaybeCollect();
}

void ignore_and_collect(List<BigStr*>* l) {
  StackRoot _root0(&l);

  mylib::MaybeCollect();
}

List<BigStr*>* collect_and_return(List<BigStr*>* l) {
  StackRoot _root0(&l);

  mylib::MaybeCollect();
  return l;
}

BigStr* collect_and_slice(BigStr* s) {
  StackRoot _root0(&s);

  mylib::MaybeCollect();
  return s->slice(1);
}

ctx_Stasher::ctx_Stasher(List<BigStr*>* l) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->l)));
  this->l = l;
}

ctx_Stasher::~ctx_Stasher() {
  print_list(this->l);
  gHeap.PopRoot();
}

void no_collect() {
  List<BigStr*>* l = nullptr;
  StackRoot _root0(&l);

  l = NewList<BigStr*>(std::initializer_list<BigStr*>{str0, str1});
  print_list(l);
}

void simple_collect() {
  List<BigStr*>* l1 = nullptr;
  List<BigStr*>* l2 = nullptr;
  StackRoot _root0(&l1);
  StackRoot _root1(&l2);

  l1 = NewList<BigStr*>(std::initializer_list<BigStr*>{str2, str3});
  l2 = NewList<BigStr*>(std::initializer_list<BigStr*>{str4, str5});
  print_list(l2);
  if (len(l1)) {
    mylib::MaybeCollect();
  }
  print_list(l1);
}

void indirect_collect() {
  List<BigStr*>* l = nullptr;
  StackRoot _root0(&l);

  l = NewList<BigStr*>(std::initializer_list<BigStr*>{str6, str7});
  calls_collect();
  print_list(l);
}

void arg_roots() {
  List<BigStr*>* l1 = nullptr;
  List<BigStr*>* l2 = nullptr;
  StackRoot _root0(&l1);
  StackRoot _root1(&l2);

  l1 = NewList<BigStr*>(std::initializer_list<BigStr*>{str8});
  ignore_and_collect(l1);
  print_list(l1);
  l2 = collect_and_return(NewList<BigStr*>(std::initializer_list<BigStr*>{str9, str10}));
  print_list(l2);
}

void alias() {
  List<BigStr*>* l1 = nullptr;
  List<BigStr*>* l2 = nullptr;
  StackRoot _root0(&l1);
  StackRoot _root1(&l2);

  l1 = NewList<BigStr*>(std::initializer_list<BigStr*>{str11, str12});
  l2 = l1;
  mylib::MaybeCollect();
  print_list(l2);
}

void collect_scoped_resource() {
  {  // with
    ctx_Stasher ctx{NewList<BigStr*>(std::initializer_list<BigStr*>{str13, str14})};

    mylib::MaybeCollect();
  }
}

void collect_in_loop() {
  for (ListIter<BigStr*> it(NewList<BigStr*>(std::initializer_list<BigStr*>{str15, str16})); !it.Done(); it.Next()) {
    BigStr* s = it.Value();
    StackRoot _for(&s  );
    mylib::MaybeCollect();
    print(s);
  }
}

void collect_in_comprehension() {
  List<BigStr*>* l = nullptr;
  StackRoot _root0(&l);

  l = Alloc<List<BigStr*>>();
  for (ListIter<BigStr*> it(NewList<BigStr*>(std::initializer_list<BigStr*>{str18, str19})); !it.Done(); it.Next()) {
    BigStr* s = it.Value();
    l->append(StrFormat("%s", collect_and_slice(s)));
  }
  for (ListIter<BigStr*> it(l); !it.Done(); it.Next()) {
    BigStr* s = it.Value();
    StackRoot _for(&s  );
    print(s);
  }
}

void run_tests() {
  no_collect();
  simple_collect();
  indirect_collect();
  arg_roots();
  alias();
  collect_scoped_resource();
}

void run_benchmarks() {
  ;  // pass
}

}  // define namespace gc_stack_roots

int main(int argc, char **argv) {
  gHeap.Init();

  char* b = getenv("BENCHMARK");
  if (b && strlen(b)) {  // match Python's logic
    fprintf(stderr, "Benchmarking...\n");
    gc_stack_roots::run_benchmarks();
  } else {
    gc_stack_roots::run_tests();
  }

  gHeap.CleanProcessExit();
}