// examples/containers translated by mycpp

// BEGIN mycpp output

#include "mycpp/runtime.h"

GLOBAL_STR(str0, "foo");
GLOBAL_STR(str1, "spam");
GLOBAL_STR(str2, "eggs");
GLOBAL_STR(str3, "a");
GLOBAL_STR(str4, "b");
GLOBAL_STR(str5, "foo");
GLOBAL_STR(str6, "bar");
GLOBAL_STR(str7, "spam");
GLOBAL_STR(str8, "foo");
GLOBAL_STR(str9, "foo");
GLOBAL_STR(str10, "local_list = %d");
GLOBAL_STR(str11, "len(intlist) = %d");
GLOBAL_STR(str12, "i = %d");
GLOBAL_STR(str13, "1? %d");
GLOBAL_STR(str14, "42? %d");
GLOBAL_STR(str15, "len() after del = %d");
GLOBAL_STR(str16, "a");
GLOBAL_STR(str17, "b");
GLOBAL_STR(str18, "len(strlist) = %d");
GLOBAL_STR(str19, "s = %s");
GLOBAL_STR(str20, "a? %d");
GLOBAL_STR(str21, "a");
GLOBAL_STR(str22, "foo? %d");
GLOBAL_STR(str23, "foo");
GLOBAL_STR(str24, "len(strlist) = %d");
GLOBAL_STR(str25, "x = %s");
GLOBAL_STR(str26, "len(blank) = %d");
GLOBAL_STR(str27, "hello");
GLOBAL_STR(str28, "myint = %d");
GLOBAL_STR(str29, "mystr = %s");
GLOBAL_STR(str30, "yes");
GLOBAL_STR(str31, "no");
GLOBAL_STR(str32, "yes");
GLOBAL_STR(str33, "no");
GLOBAL_STR(str34, "foo");
GLOBAL_STR(str35, "foo");
GLOBAL_STR(str36, "bar");
GLOBAL_STR(str37, "yes");
GLOBAL_STR(str38, "no");
GLOBAL_STR(str39, "glist_int = %d");
GLOBAL_STR(str40, "glist_str = %d");
GLOBAL_STR(str41, "foo");
GLOBAL_STR(str42, "len(d) = %d");
GLOBAL_STR(str43, "foo");
GLOBAL_STR(str44, "len(d) = %d");
GLOBAL_STR(str45, "a");
GLOBAL_STR(str46, "b");
GLOBAL_STR(str47, "c");
GLOBAL_STR(str48, "a");
GLOBAL_STR(str49, "%s %d");
GLOBAL_STR(str50, "len gEmptyDict = %d");
GLOBAL_STR(str51, "len gdict = %d");
GLOBAL_STR(str52, "len gdict_is = %d");
GLOBAL_STR(str53, "len gdict_ss = %d");
GLOBAL_STR(str54, "gdict[\"a\"] = %d");
GLOBAL_STR(str55, "a");
GLOBAL_STR(str56, "gdict_is[5] = %s");
GLOBAL_STR(str57, "gdict_ss[\"foo\"] = %s");
GLOBAL_STR(str58, "foo");
GLOBAL_STR(str59, "foo");
GLOBAL_STR(str60, "bar");
GLOBAL_STR(str61, "foo = %d");
GLOBAL_STR(str62, "foo");
GLOBAL_STR(str63, "bar");
GLOBAL_STR(str64, "bar is a member");
GLOBAL_STR(str65, "345 yes");
GLOBAL_STR(str66, "345 no");
GLOBAL_STR(str67, "357 yes");
GLOBAL_STR(str68, "357 no");
GLOBAL_STR(str69, "tu 345 yes");
GLOBAL_STR(str70, "tu 345 no");
GLOBAL_STR(str71, "tu 357 yes");
GLOBAL_STR(str72, "tu 357 no");
GLOBAL_STR(str73, "hi");
GLOBAL_STR(str74, "hi");
GLOBAL_STR(str75, "bye");
GLOBAL_STR(str76, "hi yes");
GLOBAL_STR(str77, "hi no");
GLOBAL_STR(str78, "hi");
GLOBAL_STR(str79, "bye");
GLOBAL_STR(str80, "hi yes");
GLOBAL_STR(str81, "hi no");
GLOBAL_STR(str82, "");
GLOBAL_STR(str83, "");
GLOBAL_STR(str84, "");
GLOBAL_STR(str85, "");
GLOBAL_STR(str86, "foo");
GLOBAL_STR(str87, "Appended %d items to 2 lists");

namespace containers {  // forward declare

  class Point;

}  // forward declare namespace containers

namespace containers {  // declare

extern BigStr* gstr;
extern List<int>* glist_int;
extern List<BigStr*>* glist_str;
extern Dict<BigStr*, BigStr*>* gEmptyDict;
extern Dict<BigStr*, int>* gdict;
extern Dict<int, BigStr*>* gdict_is;
extern Dict<BigStr*, BigStr*>* gdict_ss;
void ListDemo();
class Point {
 public:
  Point(int x, int y);
  int x;
  int y;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(0, sizeof(Point));
  }

  DISALLOW_COPY_AND_ASSIGN(Point)
};

void TupleDemo();
void DictDemo();
void ContainsDemo();
void run_tests();
void run_benchmarks();

}  // declare namespace containers

namespace containers {  // define

BigStr* gstr = str0;
GLOBAL_LIST(glist_int, int, 2, {1 COMMA 2});
GLOBAL_LIST(glist_str, BigStr*, 2, {str1 COMMA str2});
GLOBAL_DICT(gEmptyDict, BigStr*, BigStr*, 0, {}, {});
GLOBAL_DICT(gdict, BigStr*, int, 2, {str3 COMMA str4}, {42 COMMA 43});
GLOBAL_DICT(gdict_is, int, BigStr*, 3, {5 COMMA 6 COMMA 7}, {str5 COMMA str6 COMMA str7});
GLOBAL_DICT(gdict_ss, BigStr*, BigStr*, 1, {str8}, {str9});

void ListDemo() {
  List<int>* intlist = nullptr;
  List<int>* local_list = nullptr;
  List<BigStr*>* strlist = nullptr;
  BigStr* x = nullptr;
  BigStr* no_str = nullptr;
  List<BigStr*>* blank = nullptr;
  intlist = Alloc<List<int>>();
  intlist->append(1);
  intlist->append(2);
  intlist->append(3);
  local_list = NewList<int>(std::initializer_list<int>{1, 2});
  mylib::print_stderr(StrFormat("local_list = %d", len(local_list)));
  intlist->set(1, 42);
  mylib::print_stderr(StrFormat("len(intlist) = %d", len(intlist)));
  for (ListIter<int> it(intlist); !it.Done(); it.Next()) {
    int i = it.Value();
    mylib::print_stderr(StrFormat("i = %d", i));
  }
  mylib::print_stderr(StrFormat("1? %d", list_contains(intlist, 1)));
  mylib::print_stderr(StrFormat("42? %d", list_contains(intlist, 42)));
  intlist->clear();
  mylib::print_stderr(StrFormat("len() after del = %d", len(intlist)));
  strlist = Alloc<List<BigStr*>>();
  strlist->append(str16);
  strlist->append(str17);
  mylib::print_stderr(StrFormat("len(strlist) = %d", len(strlist)));
  for (ListIter<BigStr*> it(strlist); !it.Done(); it.Next()) {
    BigStr* s = it.Value();
    StackRoot _for(&s  );
    mylib::print_stderr(StrFormat("s = %s", s));
  }
  mylib::print_stderr(StrFormat("a? %d", list_contains(strlist, str21)));
  mylib::print_stderr(StrFormat("foo? %d", list_contains(strlist, str23)));
  mylib::print_stderr(StrFormat("len(strlist) = %d", len(strlist)));
  x = strlist->pop();
  mylib::print_stderr(StrFormat("x = %s", x));
  no_str = nullptr;
  blank = list_repeat(no_str, 3);
  mylib::print_stderr(StrFormat("len(blank) = %d", len(blank)));
}

Point::Point(int x, int y) {
  this->x = x;
  this->y = y;
}

void TupleDemo() {
  Tuple2<int, BigStr*>* t2 = nullptr;
  int myint;
  BigStr* mystr = nullptr;
  int x;
  containers::Point* p = nullptr;
  BigStr* s = nullptr;
  t2 = (Alloc<Tuple2<int, BigStr*>>(3, str27));
  Tuple2<int, BigStr*>* tup0 = t2;
  myint = tup0->at0();
  mystr = tup0->at1();
  mylib::print_stderr(StrFormat("myint = %d", myint));
  mylib::print_stderr(StrFormat("mystr = %s", mystr));
  x = 3;
  if ((x == 3 || x == 4 || x == 5)) {
    print(str30);
  }
  else {
    print(str31);
  }
  p = Alloc<Point>(3, 4);
  if ((p->x == 3 || p->x == 4 || p->x == 5)) {
    print(str32);
  }
  else {
    print(str33);
  }
  s = str34;
  if ((str_equals(s, str35) || str_equals(s, str36))) {
    print(str37);
  }
  else {
    print(str38);
  }
  mylib::print_stderr(StrFormat("glist_int = %d", len(glist_int)));
  mylib::print_stderr(StrFormat("glist_str = %d", len(glist_str)));
}

void DictDemo() {
  Dict<BigStr*, int>* d = nullptr;
  Dict<BigStr*, int>* ordered = nullptr;
  Dict<BigStr*, int>* lit = nullptr;
  d = Alloc<Dict<BigStr*, int>>();
  d->set(str41, 42);
  ordered = Alloc<Dict<BigStr*, int>>();
  ordered->set(str45, 10);
  ordered->set(str46, 11);
  ordered->set(str47, 12);
  ordered->set(str48, 50);
  for (DictIter<BigStr*, int> it(ordered); !it.Done(); it.Next()) {
    BigStr* k = it.Key();
    int v = it.Value();
    mylib::print_stderr(StrFormat("%s %d", k, v));
  }
  mylib::print_stderr(StrFormat("len gEmptyDict = %d", len(gEmptyDict)));
  mylib::print_stderr(StrFormat("len gdict = %d", len(gdict)));
  mylib::print_stderr(StrFormat("len gdict_is = %d", len(gdict_is)));
  mylib::print_stderr(StrFormat("len gdict_ss = %d", len(gdict_ss)));
  mylib::print_stderr(StrFormat("gdict[\"a\"] = %d", gdict->at(str55)));
  mylib::print_stderr(StrFormat("gdict_is[5] = %s", gdict_is->at(5)));
  mylib::print_stderr(StrFormat("gdict_ss[\"foo\"] = %s", gdict_ss->at(str58)));
  lit = Alloc<Dict<BigStr*, int>>(std::initializer_list<BigStr*>{str59, str60}, std::initializer_list<int>{42, 43});
  mylib::print_stderr(StrFormat("foo = %d", lit->at(str62)));
  if (dict_contains(lit, str63)) {
    mylib::print_stderr(str64);
  }
}

void ContainsDemo() {
  int x;
  BigStr* s = nullptr;
  x = 4;
  if (list_contains(NewList<int>(std::initializer_list<int>{3, 4, 5}), x)) {
    print(str65);
  }
  else {
    print(str66);
  }
  if (list_contains(NewList<int>(std::initializer_list<int>{3, 5, 7}), x)) {
    print(str67);
  }
  else {
    print(str68);
  }
  x = 4;
  if ((x == 3 || x == 4 || x == 5)) {
    print(str69);
  }
  else {
    print(str70);
  }
  if ((x == 3 || x == 5 || x == 7)) {
    print(str71);
  }
  else {
    print(str72);
  }
  s = str73;
  if ((str_equals(s, str74) || str_equals(s, str75))) {
    print(str76);
  }
  else {
    print(str77);
  }
  if ((!str_equals(s, str78) && !str_equals(s, str79))) {
    print(str80);
  }
  else {
    print(str81);
  }
}

void run_tests() {
  List<int>* a = nullptr;
  ListDemo();
  mylib::print_stderr(str82);
  TupleDemo();
  mylib::print_stderr(str83);
  DictDemo();
  mylib::print_stderr(str84);
  ContainsDemo();
  mylib::print_stderr(str85);
  a = Alloc<List<int>>();
  a->append(42);
}

void run_benchmarks() {
  int n;
  int i;
  List<int>* intlist = nullptr;
  List<BigStr*>* strlist = nullptr;
  n = 1000000;
  i = 0;
  intlist = Alloc<List<int>>();
  strlist = Alloc<List<BigStr*>>();
  while (i < n) {
    intlist->append(i);
    strlist->append(str86);
    i += 1;
  }
  mylib::print_stderr(StrFormat("Appended %d items to 2 lists", n));
}

}  // define namespace containers

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

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

  gHeap.CleanProcessExit();
}