Merge "Fix C++ ForEach reflection (bad usrData args)."
diff --git a/slang_rs_reflection.cpp b/slang_rs_reflection.cpp
index e667a94..3e0e88d 100644
--- a/slang_rs_reflection.cpp
+++ b/slang_rs_reflection.cpp
@@ -1221,7 +1221,7 @@
                        << (FieldAllocSize - FieldStoreSize)
                        << ");" << std::endl;
 
-          Pos = FieldOffset + FieldAllocSize;
+        Pos = FieldOffset + FieldAllocSize;
       }
 
       // There maybe some padding after the struct
diff --git a/slang_rs_reflection_base.h b/slang_rs_reflection_base.h
index 1f96723..8667e0d 100644
--- a/slang_rs_reflection_base.h
+++ b/slang_rs_reflection_base.h
@@ -71,6 +71,8 @@
 private:
 
 public:
+    typedef std::vector<std::pair<std::string, std::string> > ArgTy;
+
     virtual ~RSReflectionBase();
 
     static std::string genInitValue(const clang::APValue &Val, bool asBool=false);
diff --git a/slang_rs_reflection_cpp.cpp b/slang_rs_reflection_cpp.cpp
index 6dba8b5..6dfe141 100644
--- a/slang_rs_reflection_cpp.cpp
+++ b/slang_rs_reflection_cpp.cpp
@@ -41,8 +41,76 @@
 
 namespace slang {
 
+#define RS_TYPE_ITEM_CLASS_NAME          "Item"
+
+static const char *GetMatrixTypeName(const RSExportMatrixType *EMT) {
+  static const char *MatrixTypeCNameMap[] = {
+    "rs_matrix2x2",
+    "rs_matrix3x3",
+    "rs_matrix4x4",
+  };
+  unsigned Dim = EMT->getDim();
+
+  if ((Dim - 2) < (sizeof(MatrixTypeCNameMap) / sizeof(const char*)))
+    return MatrixTypeCNameMap[ EMT->getDim() - 2 ];
+
+  slangAssert(false && "GetMatrixTypeName : Unsupported matrix dimension");
+  return NULL;
+}
+
+
+static std::string GetTypeName(const RSExportType *ET, bool Brackets = true) {
+  switch (ET->getClass()) {
+    case RSExportType::ExportClassPrimitive: {
+      return RSExportPrimitiveType::getRSReflectionType(
+          static_cast<const RSExportPrimitiveType*>(ET))->c_name;
+    }
+    case RSExportType::ExportClassPointer: {
+      const RSExportType *PointeeType =
+          static_cast<const RSExportPointerType*>(ET)->getPointeeType();
+
+      if (PointeeType->getClass() != RSExportType::ExportClassRecord)
+        return "android::sp<android::RSC::Allocation>";
+      else
+        return PointeeType->getElementName();
+    }
+    case RSExportType::ExportClassVector: {
+      const RSExportVectorType *EVT =
+          static_cast<const RSExportVectorType*>(ET);
+      std::stringstream VecName;
+      VecName << EVT->getRSReflectionType(EVT)->rs_c_vector_prefix
+              << EVT->getNumElement();
+      return VecName.str();
+    }
+    case RSExportType::ExportClassMatrix: {
+      return GetMatrixTypeName(static_cast<const RSExportMatrixType*>(ET));
+    }
+    case RSExportType::ExportClassConstantArray: {
+      // TODO: Fix this for C arrays!
+      const RSExportConstantArrayType* CAT =
+          static_cast<const RSExportConstantArrayType*>(ET);
+      std::string ElementTypeName = GetTypeName(CAT->getElementType());
+      if (Brackets) {
+        ElementTypeName.append("[]");
+      }
+      return ElementTypeName;
+    }
+    case RSExportType::ExportClassRecord: {
+      // TODO: Fix for C structs!
+      return ET->getElementName() + "." RS_TYPE_ITEM_CLASS_NAME;
+    }
+    default: {
+      slangAssert(false && "Unknown class of type");
+    }
+  }
+
+  return "";
+}
+
+
 RSReflectionCpp::RSReflectionCpp(const RSContext *con)
     : RSReflectionBase(con) {
+  clear();
 }
 
 RSReflectionCpp::~RSReflectionCpp() {
@@ -72,8 +140,6 @@
   return true;
 }
 
-typedef std::vector<std::pair<std::string, std::string> > ArgTy;
-
 
 #define RS_TYPE_CLASS_NAME_PREFIX        "ScriptField_"
 
@@ -107,7 +173,7 @@
     RSReflectionTypeData rtd;
     ev->getType()->convertToRTD(&rtd);
     if (!ev->isConst()) {
-      write(string(rtd.type->c_name) + " __" + ev->getName() + ";");
+      write(GetTypeName(ev->getType()) + " __" + ev->getName() + ";");
     }
   }
   decIndent();
@@ -124,29 +190,7 @@
   slot = 0;
   for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
          E = mRSContext->export_vars_end(); I != E; I++, slot++) {
-    const RSExportVar *ev = *I;
-    RSReflectionTypeData rtd;
-    ev->getType()->convertToRTD(&rtd);
-
-    if (!ev->isConst()) {
-      write(string("void set_") + ev->getName() + "(" + rtd.type->c_name +
-            " v) {");
-      stringstream tmp;
-      tmp << slot;
-      write(string("    setVar(") + tmp.str() + ", &v, sizeof(v));");
-      write(string("    __") + ev->getName() + " = v;");
-      write("}");
-    }
-    write(string(rtd.type->c_name) + " get_" + ev->getName() + "() const {");
-    if (ev->isConst()) {
-      const clang::APValue &val = ev->getInit();
-      bool isBool = !strcmp(rtd.type->c_name, "bool");
-      write(string("    return ") + genInitValue(val, isBool) + ";");
-    } else {
-      write(string("    return __") + ev->getName() + ";");
-    }
-    write("}");
-    write("");
+    genExportVariable(*I);
   }
 
   // Reflect export for each functions
@@ -159,27 +203,32 @@
       continue;
     }
 
-    stringstream tmp;
-    tmp << "void forEach_" << ef->getName() << "(";
-    if (ef->hasIn() && (ef->hasOut() || ef->hasReturn())) {
-      tmp << "android::sp<const android::RSC::Allocation> ain";
-      tmp << ", android::sp<const android::RSC::Allocation> aout";
-    } else if (ef->hasIn()) {
-      tmp << "android::sp<const android::RSC::Allocation> ain";
-    } else {
-      tmp << "android::sp<const android::RSC::Allocation> aout";
+    ArgTy Args;
+    stringstream ss;
+    ss << "void forEach_" << ef->getName() << "(";
+
+    if (ef->hasIn()) {
+      Args.push_back(std::make_pair(
+          "android::sp<const android::RSC::Allocation>", "ain"));
     }
 
-    if (ef->getParamPacketType()) {
+    if (ef->hasOut() || ef->hasReturn()) {
+      Args.push_back(std::make_pair(
+          "android::sp<const android::RSC::Allocation>", "aout"));
+    }
+
+    const RSExportRecordType *ERT = ef->getParamPacketType();
+    if (ERT) {
       for (RSExportForEach::const_param_iterator i = ef->params_begin(),
            e = ef->params_end(); i != e; i++) {
         RSReflectionTypeData rtd;
         (*i)->getType()->convertToRTD(&rtd);
-        tmp << rtd.type->c_name << " " << (*i)->getName();
+        Args.push_back(std::make_pair(rtd.type->c_name, (*i)->getName()));
       }
     }
-    tmp << ");";
-    write(tmp);
+    makeArgs(ss, Args);
+    ss << ");";
+    write(ss);
   }
 
 
@@ -227,7 +276,7 @@
 }
 
 bool RSReflectionCpp::makeImpl(const std::string &baseClass) {
-  startFile(mClassName + ".h");
+  startFile(mClassName + ".cpp");
 
   write("");
   write("#include \"" + mClassName + ".h\"");
@@ -243,9 +292,9 @@
   write("\n");
   stringstream ss;
   ss << mClassName << "::" << mClassName
-     << "(android::sp<android::RSC::RS> rs, "
-        "const char *cacheDir, size_t cacheDirLength) :\n"
-     << "        ScriptC(rs, __txt, sizeof(__txt), \""
+     << "(android::sp<android::RSC::RS> rs, const char *cacheDir, "
+        "size_t cacheDirLength) :\n"
+        "        ScriptC(rs, __txt, sizeof(__txt), \""
      << mClassName << "\", " << mClassName.length()
      << ", cacheDir, cacheDirLength) {";
   write(ss);
@@ -271,27 +320,55 @@
     }
 
     stringstream tmp;
+    ArgTy Args;
     tmp << "void " << mClassName << "::forEach_" << ef->getName() << "(";
-    if (ef->hasIn() && (ef->hasOut() || ef->hasReturn())) {
-      tmp << "android::sp<const android::RSC::Allocation> ain";
-      tmp << ", android::sp<const android::RSC::Allocation> aout";
-    } else if (ef->hasIn()) {
-      tmp << "android::sp<const android::RSC::Allocation> ain";
-    } else {
-      tmp << "android::sp<const android::RSC::Allocation> aout";
+
+    if (ef->hasIn()) {
+      Args.push_back(std::make_pair(
+          "android::sp<const android::RSC::Allocation>", "ain"));
     }
+
+    if (ef->hasOut() || ef->hasReturn()) {
+      Args.push_back(std::make_pair(
+          "android::sp<const android::RSC::Allocation>", "aout"));
+    }
+
+    const RSExportRecordType *ERT = ef->getParamPacketType();
+    if (ERT) {
+      for (RSExportForEach::const_param_iterator i = ef->params_begin(),
+           e = ef->params_end(); i != e; i++) {
+        RSReflectionTypeData rtd;
+        (*i)->getType()->convertToRTD(&rtd);
+        Args.push_back(std::make_pair(rtd.type->c_name, (*i)->getName()));
+      }
+    }
+    makeArgs(tmp, Args);
+
     tmp << ") {";
     write(tmp);
     tmp.str("");
 
-    tmp << "    forEach(" << slot << ", ";
-    if (ef->hasIn() && (ef->hasOut() || ef->hasReturn())) {
-      tmp << "ain, aout, NULL, 0);";
-    } else if (ef->hasIn()) {
-      tmp << "ain, NULL, 0);";
-    } else {
-      tmp << "aout, NULL, 0);";
+    std::string FieldPackerName = ef->getName() + "_fp";
+    if (ERT) {
+      if (genCreateFieldPacker(ERT, FieldPackerName.c_str())) {
+        genPackVarOfType(ERT, NULL, FieldPackerName.c_str());
+      }
     }
+    tmp << "    forEach(" << slot << ", ";
+
+    if (ef->hasIn()) {
+      tmp << "ain, ";
+    } else {
+      tmp << "NULL, ";
+    }
+
+    if (ef->hasOut() || ef->hasReturn()) {
+      tmp << "aout, ";
+    } else {
+      tmp << "NULL, ";
+    }
+
+    tmp << "NULL, 0);";
     write(tmp);
 
     write("}");
@@ -313,17 +390,9 @@
     size_t param_len = 0;
     if (params) {
       param_len = RSExportType::GetTypeAllocSize(params);
-      ss << "    FieldPacker __fp(" << param_len << ");";
-      write(ss);
-      for (RSExportFunc::const_param_iterator i = ef->params_begin(),
-           e = ef->params_end(); i != e; i++) {
-        RSReflectionTypeData rtd;
-        (*i)->getType()->convertToRTD(&rtd);
-        ss.str("");
-        ss << "    __fp.add(" << (*i)->getName() << ");";
-        write(ss);
+      if (genCreateFieldPacker(params, "__fp")) {
+        genPackVarOfType(params, NULL, "__fp");
       }
-
     }
 
     ss.str("");
@@ -345,6 +414,118 @@
   return true;
 }
 
+void RSReflectionCpp::genExportVariable(const RSExportVar *EV) {
+  const RSExportType *ET = EV->getType();
+
+  switch (ET->getClass()) {
+    case RSExportType::ExportClassPrimitive: {
+      genPrimitiveTypeExportVariable(EV);
+      break;
+    }
+    case RSExportType::ExportClassPointer: {
+      genPointerTypeExportVariable(EV);
+      break;
+    }
+    case RSExportType::ExportClassVector: {
+      genVectorTypeExportVariable(EV);
+      break;
+    }
+    case RSExportType::ExportClassMatrix: {
+      genMatrixTypeExportVariable(EV);
+      break;
+    }
+    case RSExportType::ExportClassConstantArray: {
+      genConstantArrayTypeExportVariable(EV);
+      break;
+    }
+    case RSExportType::ExportClassRecord: {
+      genRecordTypeExportVariable(EV);
+      break;
+    }
+    default: {
+      slangAssert(false && "Unknown class of type");
+    }
+  }
+}
+
+
+void RSReflectionCpp::genPrimitiveTypeExportVariable(const RSExportVar *EV) {
+  RSReflectionTypeData rtd;
+  EV->getType()->convertToRTD(&rtd);
+
+  if (!EV->isConst()) {
+    write(string("void set_") + EV->getName() + "(" + rtd.type->c_name +
+          " v) {");
+    stringstream tmp;
+    tmp << getNextExportVarSlot();
+    write(string("    setVar(") + tmp.str() + ", &v, sizeof(v));");
+    write(string("    __") + EV->getName() + " = v;");
+    write("}");
+  }
+  write(string(rtd.type->c_name) + " get_" + EV->getName() + "() const {");
+  if (EV->isConst()) {
+    const clang::APValue &val = EV->getInit();
+    bool isBool = !strcmp(rtd.type->c_name, "bool");
+    write(string("    return ") + genInitValue(val, isBool) + ";");
+  } else {
+    write(string("    return __") + EV->getName() + ";");
+  }
+  write("}");
+  write("");
+}
+
+void RSReflectionCpp::genPointerTypeExportVariable(const RSExportVar *EV) {
+  const RSExportType *ET = EV->getType();
+
+  slangAssert((ET->getClass() == RSExportType::ExportClassPointer) &&
+              "Variable should be type of pointer here");
+
+  std::string TypeName = GetTypeName(ET);
+  std::string VarName = EV->getName();
+
+  RSReflectionTypeData rtd;
+  EV->getType()->convertToRTD(&rtd);
+  uint32_t slot = getNextExportVarSlot();
+
+  if (!EV->isConst()) {
+    write(string("void bind_") + VarName + "(" + TypeName +
+          " v) {");
+    stringstream tmp;
+    tmp << slot;
+    write(string("    bindAllocation(v, ") + tmp.str() + ");");
+    write(string("    __") + VarName + " = v;");
+    write("}");
+  }
+  write(TypeName + " get_" + VarName + "() const {");
+  if (EV->isConst()) {
+    const clang::APValue &val = EV->getInit();
+    bool isBool = !strcmp(TypeName.c_str(), "bool");
+    write(string("    return ") + genInitValue(val, isBool) + ";");
+  } else {
+    write(string("    return __") + VarName + ";");
+  }
+  write("}");
+  write("");
+
+}
+
+void RSReflectionCpp::genVectorTypeExportVariable(const RSExportVar *EV) {
+  slangAssert(false);
+}
+
+void RSReflectionCpp::genMatrixTypeExportVariable(const RSExportVar *EV) {
+  slangAssert(false);
+}
+
+void RSReflectionCpp::genConstantArrayTypeExportVariable(
+    const RSExportVar *EV) {
+  slangAssert(false);
+}
+
+void RSReflectionCpp::genRecordTypeExportVariable(const RSExportVar *EV) {
+  slangAssert(false);
+}
+
 
 void RSReflectionCpp::makeFunctionSignature(
     std::stringstream &ss,
@@ -378,4 +559,136 @@
   }
 }
 
+void RSReflectionCpp::makeArgs(std::stringstream &ss, const ArgTy& Args) {
+  bool FirstArg = true;
+
+  for (ArgTy::const_iterator I = Args.begin(), E = Args.end(); I != E; I++) {
+    if (!FirstArg) {
+      ss << ", ";
+    } else {
+      FirstArg = false;
+    }
+
+    ss << I->first << " " << I->second;
+  }
+}
+
+bool RSReflectionCpp::genCreateFieldPacker(const RSExportType *ET,
+                                           const char *FieldPackerName) {
+  size_t AllocSize = RSExportType::GetTypeAllocSize(ET);
+
+  if (AllocSize > 0) {
+    std::stringstream ss;
+    ss << "    FieldPacker " << FieldPackerName << "("
+       << AllocSize << ");";
+    write(ss);
+    return true;
+  }
+
+  return false;
+}
+
+void RSReflectionCpp::genPackVarOfType(const RSExportType *ET,
+                                       const char *VarName,
+                                       const char *FieldPackerName) {
+  std::stringstream ss;
+  switch (ET->getClass()) {
+    case RSExportType::ExportClassPrimitive:
+    case RSExportType::ExportClassVector:
+    case RSExportType::ExportClassPointer:
+    case RSExportType::ExportClassMatrix: {
+      RSReflectionTypeData rtd;
+      ET->convertToRTD(&rtd);
+      ss << "    " << FieldPackerName << ".add(" << VarName << ");";
+      write(ss);
+      break;
+    }
+    case RSExportType::ExportClassConstantArray: {
+      /*const RSExportConstantArrayType *ECAT =
+          static_cast<const RSExportConstantArrayType *>(ET);
+
+      // TODO(zonr): more elegant way. Currently, we obtain the unique index
+      //             variable (this method involves recursive call which means
+      //             we may have more than one level loop, therefore we can't
+      //             always use the same index variable name here) name given
+      //             in the for-loop from counting the '.' in @VarName.
+      unsigned Level = 0;
+      size_t LastDotPos = 0;
+      std::string ElementVarName(VarName);
+
+      while (LastDotPos != std::string::npos) {
+        LastDotPos = ElementVarName.find_first_of('.', LastDotPos + 1);
+        Level++;
+      }
+      std::string IndexVarName("ct");
+      IndexVarName.append(llvm::utostr_32(Level));
+
+      C.indent() << "for (int " << IndexVarName << " = 0; " <<
+                          IndexVarName << " < " << ECAT->getSize() << "; " <<
+                          IndexVarName << "++)";
+      C.startBlock();
+
+      ElementVarName.append("[" + IndexVarName + "]");
+      genPackVarOfType(C, ECAT->getElementType(), ElementVarName.c_str(),
+                       FieldPackerName);
+
+      C.endBlock();*/
+      break;
+    }
+    case RSExportType::ExportClassRecord: {
+      const RSExportRecordType *ERT =
+          static_cast<const RSExportRecordType*>(ET);
+      // Relative pos from now on in field packer
+      unsigned Pos = 0;
+
+      for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(),
+               E = ERT->fields_end();
+           I != E;
+           I++) {
+        const RSExportRecordType::Field *F = *I;
+        std::string FieldName;
+        size_t FieldOffset = F->getOffsetInParent();
+        size_t FieldStoreSize = RSExportType::GetTypeStoreSize(F->getType());
+        size_t FieldAllocSize = RSExportType::GetTypeAllocSize(F->getType());
+
+        if (VarName != NULL)
+          FieldName = VarName + ("." + F->getName());
+        else
+          FieldName = F->getName();
+
+        if (FieldOffset > Pos) {
+          ss.str("");
+          ss << "    " << FieldPackerName << ".skip("
+             << (FieldOffset - Pos) << ");";
+          write(ss);
+        }
+
+        genPackVarOfType(F->getType(), FieldName.c_str(), FieldPackerName);
+
+        // There is padding in the field type
+        if (FieldAllocSize > FieldStoreSize) {
+          ss.str("");
+          ss << "    " << FieldPackerName << ".skip("
+             << (FieldAllocSize - FieldStoreSize) << ");";
+          write(ss);
+        }
+
+        Pos = FieldOffset + FieldAllocSize;
+      }
+
+      // There maybe some padding after the struct
+      if (RSExportType::GetTypeAllocSize(ERT) > Pos) {
+        ss.str("");
+        ss << "    " << FieldPackerName << ".skip("
+           << RSExportType::GetTypeAllocSize(ERT) - Pos << ");";
+        write(ss);
+      }
+      break;
+    }
+    default: {
+      slangAssert(false && "Unknown class of type");
+    }
+  }
+}
+
 }  // namespace slang
diff --git a/slang_rs_reflection_cpp.h b/slang_rs_reflection_cpp.h
index 226bc5b..de7e824 100644
--- a/slang_rs_reflection_cpp.h
+++ b/slang_rs_reflection_cpp.h
@@ -32,6 +32,28 @@
 
 
  private:
+  unsigned int mNextExportVarSlot;
+  unsigned int mNextExportFuncSlot;
+  unsigned int mNextExportForEachSlot;
+
+  inline void clear() {
+    mNextExportVarSlot = 0;
+    mNextExportFuncSlot = 0;
+    mNextExportForEachSlot = 0;
+  }
+
+  inline unsigned int getNextExportVarSlot() {
+    return mNextExportVarSlot++;
+  }
+
+  inline unsigned int getNextExportFuncSlot() {
+    return mNextExportFuncSlot++;
+  }
+
+  inline unsigned int getNextExportForEachSlot() {
+    return mNextExportForEachSlot++;
+  }
+
   bool makeHeader(const std::string &baseClass);
   bool makeImpl(const std::string &baseClass);
   void makeFunctionSignature(std::stringstream &ss, bool isDefinition,
@@ -39,7 +61,29 @@
   bool writeBC();
 
   bool startScriptHeader();
-};  // class RSReflection
+
+  // Produce an argument string of the form "T1 t, T2 u, T3 v".
+  void makeArgs(std::stringstream &ss, const ArgTy& Args);
+
+  // Write out code for an export variable.
+  void genExportVariable(const RSExportVar *EV);
+
+  void genPrimitiveTypeExportVariable(const RSExportVar *EV);
+  void genPointerTypeExportVariable(const RSExportVar *EV);
+  void genVectorTypeExportVariable(const RSExportVar *EV);
+  void genMatrixTypeExportVariable(const RSExportVar *EV);
+  void genConstantArrayTypeExportVariable(const RSExportVar *EV);
+  void genRecordTypeExportVariable(const RSExportVar *EV);
+
+  // Write out a local FieldPacker (if necessary).
+  bool genCreateFieldPacker(const RSExportType *T,
+                            const char *FieldPackerName);
+
+  // Populate (write) the FieldPacker with add() operations.
+  void genPackVarOfType(const RSExportType *ET,
+                        const char *VarName,
+                        const char *FieldPackerName);
+};  // class RSReflectionCpp
 
 }   // namespace slang
 
diff --git a/tests/P_export_types/export_types.rs b/tests/P_export_types/export_types.rs
index a885a18..f6c0f3c 100644
--- a/tests/P_export_types/export_types.rs
+++ b/tests/P_export_types/export_types.rs
@@ -28,5 +28,6 @@
 rs_program_store program_store;
 rs_font font;
 
-
+float *fp;
+int *ip;
 
diff --git a/tests/P_kernel_cpp/stdout.txt.expect b/tests/P_kernel_cpp/stdout.txt.expect
index e69de29..9bb7004 100644
--- a/tests/P_kernel_cpp/stdout.txt.expect
+++ b/tests/P_kernel_cpp/stdout.txt.expect
@@ -0,0 +1,2 @@
+Generating ScriptC_kernel_cpp.h
+Generating ScriptC_kernel_cpp.cpp