<commit_before>//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// These tablegen backends emit Clang diagnostics tables.
//
//===----------------------------------------------------------------------===//

#include "ClangDiagnosticsEmitter.h"
#include "llvm/TableGen/Record.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/VectorExtras.h"
#include <map>
#include <algorithm>
#include <functional>
using namespace llvm;

//===----------------------------------------------------------------------===//
// Diagnostic category computation code.
//===----------------------------------------------------------------------===//

namespace {
class DiagGroupParentMap {
  RecordKeeper &Records;
  std::map<const Record*, std::vector<Record*> > Mapping;
public:
  DiagGroupParentMap(RecordKeeper &records) : Records(records) {
    std::vector<Record*> DiagGroups
      = Records.getAllDerivedDefinitions("DiagGroup");
    for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
      std::vector<Record*> SubGroups =
        DiagGroups[i]->getValueAsListOfDefs("SubGroups");
      for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
        Mapping[SubGroups[j]].push_back(DiagGroups[i]);
    }
  }

  const std::vector<Record*> &getParents(const Record *Group) {
    return Mapping[Group];
  }
};
} // end anonymous namespace.

static std::string
getCategoryFromDiagGroup(const Record *Group,
                         DiagGroupParentMap &DiagGroupParents) {
  // If the DiagGroup has a category, return it.
  std::string CatName = Group->getValueAsString("CategoryName");
  if (!CatName.empty()) return CatName;

  // The diag group may the subgroup of one or more other diagnostic groups,
  // check these for a category as well.
  const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
  for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
    CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
    if (!CatName.empty()) return CatName;
  }
  return "";
}

/// getDiagnosticCategory - Return the category that the specified diagnostic
/// lives in.
static std::string getDiagnosticCategory(const Record *R,
                                         DiagGroupParentMap &DiagGroupParents) {
  // If the diagnostic is in a group, and that group has a category, use it.
  if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) {
    // Check the diagnostic's diag group for a category.
    std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
                                                   DiagGroupParents);
    if (!CatName.empty()) return CatName;
  }

  // If the diagnostic itself has a category, get it.
  return R->getValueAsString("CategoryName");
}

namespace {
  class DiagCategoryIDMap {
    RecordKeeper &Records;
    StringMap<unsigned> CategoryIDs;
    std::vector<std::string> CategoryStrings;
  public:
    DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
      DiagGroupParentMap ParentInfo(Records);

      // The zero'th category is "".
      CategoryStrings.push_back("");
      CategoryIDs[""] = 0;

      std::vector<Record*> Diags =
      Records.getAllDerivedDefinitions("Diagnostic");
      for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
        std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
        if (Category.empty()) continue;  // Skip diags with no category.

        unsigned &ID = CategoryIDs[Category];
        if (ID != 0) continue;  // Already seen.

        ID = CategoryStrings.size();
        CategoryStrings.push_back(Category);
      }
    }

    unsigned getID(StringRef CategoryString) {
      return CategoryIDs[CategoryString];
    }

    typedef std::vector<std::string>::iterator iterator;
    iterator begin() { return CategoryStrings.begin(); }
    iterator end() { return CategoryStrings.end(); }
  };
} // end anonymous namespace.

//===----------------------------------------------------------------------===//
// Warning Tables (.inc file) generation.
//===----------------------------------------------------------------------===//

void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
  // Write the #if guard
  if (!Component.empty()) {
    std::string ComponentName = StringRef(Component).upper();
    OS << "#ifdef " << ComponentName << "START\n";
    OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
       << ",\n";
    OS << "#undef " << ComponentName << "START\n";
    OS << "#endif\n\n";
  }

  const std::vector<Record*> &Diags =
    Records.getAllDerivedDefinitions("Diagnostic");

  DiagCategoryIDMap CategoryIDs(Records);
  DiagGroupParentMap DGParentMap(Records);

  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    const Record &R = *Diags[i];
    // Filter by component.
    if (!Component.empty() && Component != R.getValueAsString("Component"))
      continue;

    OS << "DIAG(" << R.getName() << ", ";
    OS << R.getValueAsDef("Class")->getName();
    OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName();

    // Description string.
    OS << ", \"";
    OS.write_escaped(R.getValueAsString("Text")) << '"';

    // Warning associated with the diagnostic.
    if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
      OS << ", \"";
      OS.write_escaped(DI->getDef()->getValueAsString("GroupName")) << '"';
    } else {
      OS << ", \"\"";
    }

    // SFINAE bit
    if (R.getValueAsBit("SFINAE"))
      OS << ", true";
    else
      OS << ", false";

    // Access control bit
    if (R.getValueAsBit("AccessControl"))
      OS << ", true";
    else
      OS << ", false";

    // FIXME: This condition is just to avoid temporary revlock, it can be
    // removed.
    if (R.getValue("WarningNoWerror")) {
      // Default warning has no Werror bit.
      if (R.getValueAsBit("WarningNoWerror"))
        OS << ", true";
      else
        OS << ", false";

      // Default warning show in system header bit.
      if (R.getValueAsBit("WarningShowInSystemHeader"))
        OS << ", true";
      else
        OS << ", false";
    }

    // Category number.
    OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));

    // Brief
    OS << ", \"";
    OS.write_escaped(R.getValueAsString("Brief")) << '"';

    // Explanation
    OS << ", \"";
    OS.write_escaped(R.getValueAsString("Explanation")) << '"';
    OS << ")\n";
  }
}

//===----------------------------------------------------------------------===//
// Warning Group Tables generation
//===----------------------------------------------------------------------===//

static std::string getDiagCategoryEnum(llvm::StringRef name) {
  if (name.empty())
    return "DiagCat_None";
  llvm::SmallString<256> enumName = llvm::StringRef("DiagCat_");
  for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
    enumName += isalnum(*I) ? *I : '_';
  return enumName.str();
}

namespace {
struct GroupInfo {
  std::vector<const Record*> DiagsInGroup;
  std::vector<std::string> SubGroups;
  unsigned IDNo;
};
} // end anonymous namespace.

void ClangDiagGroupsEmitter::run(raw_ostream &OS) {
  // Compute a mapping from a DiagGroup to all of its parents.
  DiagGroupParentMap DGParentMap(Records);

  // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of
  // groups to diags in the group.
  std::map<std::string, GroupInfo> DiagsInGroup;

  std::vector<Record*> Diags =
    Records.getAllDerivedDefinitions("Diagnostic");
  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    const Record *R = Diags[i];
    DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"));
    if (DI == 0) continue;
    std::string GroupName = DI->getDef()->getValueAsString("GroupName");
    DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
  }

  // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
  // groups (these are warnings that GCC supports that clang never produces).
  std::vector<Record*> DiagGroups
    = Records.getAllDerivedDefinitions("DiagGroup");
  for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
    Record *Group = DiagGroups[i];
    GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];

    std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
    for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
      GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
  }

  // Assign unique ID numbers to the groups.
  unsigned IDNo = 0;
  for (std::map<std::string, GroupInfo>::iterator
       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
    I->second.IDNo = IDNo;

  // Walk through the groups emitting an array for each diagnostic of the diags
  // that are mapped to.
  OS << "\n#ifdef GET_DIAG_ARRAYS\n";
  unsigned MaxLen = 0;
  for (std::map<std::string, GroupInfo>::iterator
       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
    MaxLen = std::max(MaxLen, (unsigned)I->first.size());

    std::vector<const Record*> &V = I->second.DiagsInGroup;
    if (!V.empty()) {
      OS << "static const short DiagArray" << I->second.IDNo << "[] = { ";
      for (unsigned i = 0, e = V.size(); i != e; ++i)
        OS << "diag::" << V[i]->getName() << ", ";
      OS << "-1 };\n";
    }

    const std::vector<std::string> &SubGroups = I->second.SubGroups;
    if (!SubGroups.empty()) {
      OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { ";
      for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) {
        std::map<std::string, GroupInfo>::iterator RI =
          DiagsInGroup.find(SubGroups[i]);
        assert(RI != DiagsInGroup.end() && "Referenced without existing?");
        OS << RI->second.IDNo << ", ";
      }
      OS << "-1 };\n";
    }
  }
  OS << "#endif // GET_DIAG_ARRAYS\n\n";

  // Emit the table now.
  OS << "\n#ifdef GET_DIAG_TABLE\n";
  for (std::map<std::string, GroupInfo>::iterator
       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
    // Group option string.
    OS << "  { ";
    OS << I->first.size() << ", ";
    OS << "\"";
    OS.write_escaped(I->first) << "\","
                               << std::string(MaxLen-I->first.size()+1, ' ');

    // Diagnostics in the group.
    if (I->second.DiagsInGroup.empty())
      OS << "0, ";
    else
      OS << "DiagArray" << I->second.IDNo << ", ";

    // Subgroups.
    if (I->second.SubGroups.empty())
      OS << 0;
    else
      OS << "DiagSubGroup" << I->second.IDNo;
    OS << " },\n";
  }
  OS << "#endif // GET_DIAG_TABLE\n\n";

  // Emit the category table next.
  DiagCategoryIDMap CategoriesByID(Records);
  OS << "\n#ifdef GET_CATEGORY_TABLE\n";
  for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(),
       E = CategoriesByID.end(); I != E; ++I)
    OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n";
  OS << "#endif // GET_CATEGORY_TABLE\n\n";
}

//===----------------------------------------------------------------------===//
// Diagnostic name index generation
//===----------------------------------------------------------------------===//

namespace {
struct RecordIndexElement
{
  RecordIndexElement() {}
  explicit RecordIndexElement(Record const &R):
    Name(R.getName()) {}

  std::string Name;
};

struct RecordIndexElementSorter :
  public std::binary_function<RecordIndexElement, RecordIndexElement, bool> {

  bool operator()(RecordIndexElement const &Lhs,
                  RecordIndexElement const &Rhs) const {
    return Lhs.Name < Rhs.Name;
  }

};

} // end anonymous namespace.

void ClangDiagsIndexNameEmitter::run(raw_ostream &OS) {
  const std::vector<Record*> &Diags =
    Records.getAllDerivedDefinitions("Diagnostic");

  std::vector<RecordIndexElement> Index;
  Index.reserve(Diags.size());
  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    const Record &R = *(Diags[i]);
    Index.push_back(RecordIndexElement(R));
  }

  std::sort(Index.begin(), Index.end(), RecordIndexElementSorter());

  for (unsigned i = 0, e = Index.size(); i != e; ++i) {
    const RecordIndexElement &R = Index[i];

    OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
  }
}
<commit_msg>Validate DiagGroup names in TableGen, they're used as command line arguments so we don't want shell meta chars in there.<commit_after>//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// These tablegen backends emit Clang diagnostics tables.
//
//===----------------------------------------------------------------------===//

#include "ClangDiagnosticsEmitter.h"
#include "llvm/TableGen/Record.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/VectorExtras.h"
#include <map>
#include <algorithm>
#include <functional>
using namespace llvm;

//===----------------------------------------------------------------------===//
// Diagnostic category computation code.
//===----------------------------------------------------------------------===//

namespace {
class DiagGroupParentMap {
  RecordKeeper &Records;
  std::map<const Record*, std::vector<Record*> > Mapping;
public:
  DiagGroupParentMap(RecordKeeper &records) : Records(records) {
    std::vector<Record*> DiagGroups
      = Records.getAllDerivedDefinitions("DiagGroup");
    for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
      std::vector<Record*> SubGroups =
        DiagGroups[i]->getValueAsListOfDefs("SubGroups");
      for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
        Mapping[SubGroups[j]].push_back(DiagGroups[i]);
    }
  }

  const std::vector<Record*> &getParents(const Record *Group) {
    return Mapping[Group];
  }
};
} // end anonymous namespace.

static std::string
getCategoryFromDiagGroup(const Record *Group,
                         DiagGroupParentMap &DiagGroupParents) {
  // If the DiagGroup has a category, return it.
  std::string CatName = Group->getValueAsString("CategoryName");
  if (!CatName.empty()) return CatName;

  // The diag group may the subgroup of one or more other diagnostic groups,
  // check these for a category as well.
  const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
  for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
    CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
    if (!CatName.empty()) return CatName;
  }
  return "";
}

/// getDiagnosticCategory - Return the category that the specified diagnostic
/// lives in.
static std::string getDiagnosticCategory(const Record *R,
                                         DiagGroupParentMap &DiagGroupParents) {
  // If the diagnostic is in a group, and that group has a category, use it.
  if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) {
    // Check the diagnostic's diag group for a category.
    std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
                                                   DiagGroupParents);
    if (!CatName.empty()) return CatName;
  }

  // If the diagnostic itself has a category, get it.
  return R->getValueAsString("CategoryName");
}

namespace {
  class DiagCategoryIDMap {
    RecordKeeper &Records;
    StringMap<unsigned> CategoryIDs;
    std::vector<std::string> CategoryStrings;
  public:
    DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
      DiagGroupParentMap ParentInfo(Records);

      // The zero'th category is "".
      CategoryStrings.push_back("");
      CategoryIDs[""] = 0;

      std::vector<Record*> Diags =
      Records.getAllDerivedDefinitions("Diagnostic");
      for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
        std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
        if (Category.empty()) continue;  // Skip diags with no category.

        unsigned &ID = CategoryIDs[Category];
        if (ID != 0) continue;  // Already seen.

        ID = CategoryStrings.size();
        CategoryStrings.push_back(Category);
      }
    }

    unsigned getID(StringRef CategoryString) {
      return CategoryIDs[CategoryString];
    }

    typedef std::vector<std::string>::iterator iterator;
    iterator begin() { return CategoryStrings.begin(); }
    iterator end() { return CategoryStrings.end(); }
  };
} // end anonymous namespace.

//===----------------------------------------------------------------------===//
// Warning Tables (.inc file) generation.
//===----------------------------------------------------------------------===//

void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
  // Write the #if guard
  if (!Component.empty()) {
    std::string ComponentName = StringRef(Component).upper();
    OS << "#ifdef " << ComponentName << "START\n";
    OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
       << ",\n";
    OS << "#undef " << ComponentName << "START\n";
    OS << "#endif\n\n";
  }

  const std::vector<Record*> &Diags =
    Records.getAllDerivedDefinitions("Diagnostic");

  DiagCategoryIDMap CategoryIDs(Records);
  DiagGroupParentMap DGParentMap(Records);

  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    const Record &R = *Diags[i];
    // Filter by component.
    if (!Component.empty() && Component != R.getValueAsString("Component"))
      continue;

    OS << "DIAG(" << R.getName() << ", ";
    OS << R.getValueAsDef("Class")->getName();
    OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName();

    // Description string.
    OS << ", \"";
    OS.write_escaped(R.getValueAsString("Text")) << '"';

    // Warning associated with the diagnostic.
    if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
      OS << ", \"";
      OS.write_escaped(DI->getDef()->getValueAsString("GroupName")) << '"';
    } else {
      OS << ", \"\"";
    }

    // SFINAE bit
    if (R.getValueAsBit("SFINAE"))
      OS << ", true";
    else
      OS << ", false";

    // Access control bit
    if (R.getValueAsBit("AccessControl"))
      OS << ", true";
    else
      OS << ", false";

    // FIXME: This condition is just to avoid temporary revlock, it can be
    // removed.
    if (R.getValue("WarningNoWerror")) {
      // Default warning has no Werror bit.
      if (R.getValueAsBit("WarningNoWerror"))
        OS << ", true";
      else
        OS << ", false";

      // Default warning show in system header bit.
      if (R.getValueAsBit("WarningShowInSystemHeader"))
        OS << ", true";
      else
        OS << ", false";
    }

    // Category number.
    OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));

    // Brief
    OS << ", \"";
    OS.write_escaped(R.getValueAsString("Brief")) << '"';

    // Explanation
    OS << ", \"";
    OS.write_escaped(R.getValueAsString("Explanation")) << '"';
    OS << ")\n";
  }
}

//===----------------------------------------------------------------------===//
// Warning Group Tables generation
//===----------------------------------------------------------------------===//

static std::string getDiagCategoryEnum(llvm::StringRef name) {
  if (name.empty())
    return "DiagCat_None";
  llvm::SmallString<256> enumName = llvm::StringRef("DiagCat_");
  for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
    enumName += isalnum(*I) ? *I : '_';
  return enumName.str();
}

namespace {
struct GroupInfo {
  std::vector<const Record*> DiagsInGroup;
  std::vector<std::string> SubGroups;
  unsigned IDNo;
};
} // end anonymous namespace.

void ClangDiagGroupsEmitter::run(raw_ostream &OS) {
  // Compute a mapping from a DiagGroup to all of its parents.
  DiagGroupParentMap DGParentMap(Records);

  // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of
  // groups to diags in the group.
  std::map<std::string, GroupInfo> DiagsInGroup;

  std::vector<Record*> Diags =
    Records.getAllDerivedDefinitions("Diagnostic");
  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    const Record *R = Diags[i];
    DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"));
    if (DI == 0) continue;
    std::string GroupName = DI->getDef()->getValueAsString("GroupName");
    DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
  }

  // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
  // groups (these are warnings that GCC supports that clang never produces).
  std::vector<Record*> DiagGroups
    = Records.getAllDerivedDefinitions("DiagGroup");
  for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
    Record *Group = DiagGroups[i];
    GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];

    std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
    for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
      GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
  }

  // Assign unique ID numbers to the groups.
  unsigned IDNo = 0;
  for (std::map<std::string, GroupInfo>::iterator
       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
    I->second.IDNo = IDNo;

  // Walk through the groups emitting an array for each diagnostic of the diags
  // that are mapped to.
  OS << "\n#ifdef GET_DIAG_ARRAYS\n";
  unsigned MaxLen = 0;
  for (std::map<std::string, GroupInfo>::iterator
       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
    MaxLen = std::max(MaxLen, (unsigned)I->first.size());

    std::vector<const Record*> &V = I->second.DiagsInGroup;
    if (!V.empty()) {
      OS << "static const short DiagArray" << I->second.IDNo << "[] = { ";
      for (unsigned i = 0, e = V.size(); i != e; ++i)
        OS << "diag::" << V[i]->getName() << ", ";
      OS << "-1 };\n";
    }

    const std::vector<std::string> &SubGroups = I->second.SubGroups;
    if (!SubGroups.empty()) {
      OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { ";
      for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) {
        std::map<std::string, GroupInfo>::iterator RI =
          DiagsInGroup.find(SubGroups[i]);
        assert(RI != DiagsInGroup.end() && "Referenced without existing?");
        OS << RI->second.IDNo << ", ";
      }
      OS << "-1 };\n";
    }
  }
  OS << "#endif // GET_DIAG_ARRAYS\n\n";

  // Emit the table now.
  OS << "\n#ifdef GET_DIAG_TABLE\n";
  for (std::map<std::string, GroupInfo>::iterator
       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
    // Group option string.
    OS << "  { ";
    OS << I->first.size() << ", ";
    OS << "\"";
    if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                   "0123456789!@#$%^*-+=:?")!=std::string::npos)
      throw "Invalid character in diagnostic group '" + I->first + "'";
    OS.write_escaped(I->first) << "\","
                               << std::string(MaxLen-I->first.size()+1, ' ');

    // Diagnostics in the group.
    if (I->second.DiagsInGroup.empty())
      OS << "0, ";
    else
      OS << "DiagArray" << I->second.IDNo << ", ";

    // Subgroups.
    if (I->second.SubGroups.empty())
      OS << 0;
    else
      OS << "DiagSubGroup" << I->second.IDNo;
    OS << " },\n";
  }
  OS << "#endif // GET_DIAG_TABLE\n\n";

  // Emit the category table next.
  DiagCategoryIDMap CategoriesByID(Records);
  OS << "\n#ifdef GET_CATEGORY_TABLE\n";
  for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(),
       E = CategoriesByID.end(); I != E; ++I)
    OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n";
  OS << "#endif // GET_CATEGORY_TABLE\n\n";
}

//===----------------------------------------------------------------------===//
// Diagnostic name index generation
//===----------------------------------------------------------------------===//

namespace {
struct RecordIndexElement
{
  RecordIndexElement() {}
  explicit RecordIndexElement(Record const &R):
    Name(R.getName()) {}

  std::string Name;
};

struct RecordIndexElementSorter :
  public std::binary_function<RecordIndexElement, RecordIndexElement, bool> {

  bool operator()(RecordIndexElement const &Lhs,
                  RecordIndexElement const &Rhs) const {
    return Lhs.Name < Rhs.Name;
  }

};

} // end anonymous namespace.

void ClangDiagsIndexNameEmitter::run(raw_ostream &OS) {
  const std::vector<Record*> &Diags =
    Records.getAllDerivedDefinitions("Diagnostic");

  std::vector<RecordIndexElement> Index;
  Index.reserve(Diags.size());
  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    const Record &R = *(Diags[i]);
    Index.push_back(RecordIndexElement(R));
  }

  std::sort(Index.begin(), Index.end(), RecordIndexElementSorter());

  for (unsigned i = 0, e = Index.size(); i != e; ++i) {
    const RecordIndexElement &R = Index[i];

    OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.

#include "views/controls/button/native_button_gtk.h"

#include <gtk/gtk.h>

#include <vector>

#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "views/controls/button/checkbox.h"
#include "views/controls/button/native_button.h"
#include "views/controls/button/radio_button.h"
#include "views/controls/native/native_view_host_gtk.h"
#include "views/widget/widget.h"

namespace views {

NativeButtonGtk::NativeButtonGtk(NativeButton* native_button)
    : native_button_(native_button) {
  // Associates the actual GtkWidget with the native_button so the native_button
  // is the one considered as having the focus (not the wrapper) when the
  // GtkWidget is focused directly (with a click for example).
  set_focus_view(native_button);
}

NativeButtonGtk::~NativeButtonGtk() {
}

void NativeButtonGtk::UpdateLabel() {
  if (!native_view())
    return;

  gtk_button_set_label(GTK_BUTTON(native_view()),
                       WideToUTF8(native_button_->label()).c_str());
  preferred_size_ = gfx::Size();
}

void NativeButtonGtk::UpdateFont() {
  if (!native_view())
    return;

  PangoFontDescription* pfd =
      gfx::Font::PangoFontFromGfxFont(native_button_->font());
  gtk_widget_modify_font(native_view(), pfd);
  pango_font_description_free(pfd);
  preferred_size_ = gfx::Size();
}

void NativeButtonGtk::UpdateEnabled() {
  SetEnabled(native_button_->IsEnabled());
}

void NativeButtonGtk::UpdateDefault() {
  if (!native_view())
    return;
  if (native_button_->is_default())
    gtk_widget_grab_default(native_view());
}

View* NativeButtonGtk::GetView() {
  return this;
}

void NativeButtonGtk::SetFocus() {
  // Focus the associated widget.
  Focus();
}

bool NativeButtonGtk::UsesNativeLabel() const {
  return true;
}

bool NativeButtonGtk::UsesNativeRadioButtonGroup() const {
  return true;
}

gfx::NativeView NativeButtonGtk::GetTestingHandle() const {
  return native_view();
}

gfx::Size NativeButtonGtk::GetPreferredSize() {
  if (!native_view())
    return gfx::Size();

  if (preferred_size_.IsEmpty()) {
    GtkRequisition size_request = { 0, 0 };
    gtk_widget_size_request(native_view(), &size_request);
    preferred_size_.SetSize(size_request.width, size_request.height);
  }
  return preferred_size_;
}

void NativeButtonGtk::CreateNativeControl() {
  GtkWidget* widget = gtk_button_new();
  g_signal_connect(widget, "clicked",
                   G_CALLBACK(CallClicked), this);

  // Any push button can become the default button.
  GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_DEFAULT);

  NativeControlCreated(widget);
}

void NativeButtonGtk::NativeControlCreated(GtkWidget* widget) {
  NativeControlGtk::NativeControlCreated(widget);

  UpdateFont();
  UpdateLabel();
  UpdateDefault();
}

// static
void NativeButtonGtk::CallClicked(GtkButton* widget, NativeButtonGtk* button) {
  button->OnClicked();
}

void NativeButtonGtk::OnClicked() {
  native_button_->ButtonPressed();
}

////////////////////////////////////////////////////////////////////////////////
// NativeCheckboxGtk
NativeCheckboxGtk::NativeCheckboxGtk(Checkbox* checkbox)
    : NativeButtonGtk(checkbox),
      deliver_click_event_(true) {
}

void NativeCheckboxGtk::SyncCheckState() {
  checkbox()->SetChecked(
      gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(native_view())));
}

Checkbox* NativeCheckboxGtk::checkbox() {
  return static_cast<Checkbox*>(native_button_);
}

void NativeCheckboxGtk::CreateNativeControl() {
  GtkWidget* widget = gtk_check_button_new();
  g_signal_connect(widget, "clicked",
                   G_CALLBACK(CallClicked), this);
  NativeControlCreated(widget);
}

void NativeCheckboxGtk::OnClicked() {
  // ignore event if the event is generated by
  // gtk_toggle_button_set_active below.
  if (deliver_click_event_) {
    SyncCheckState();
    NativeButtonGtk::OnClicked();
  }
}

void NativeCheckboxGtk::UpdateDefault() {
  if (!native_view())
    return;
  UpdateChecked();
}

void NativeCheckboxGtk::UpdateChecked() {
  if (!native_view())
    return;
  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(native_view()))
      != checkbox()->checked()) {
    // gtk_toggle_button_set_active emites "clicked" signal, which
    // invokes OnClicked method above. deliver_click_event_ flag is used
    // to prevent such signal to invoke OnClicked callback.
    deliver_click_event_ = false;
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(native_view()),
                                 checkbox()->checked());
    deliver_click_event_ = true;
  }
}

////////////////////////////////////////////////////////////////////////////////
NativeRadioButtonGtk::NativeRadioButtonGtk(RadioButton* radio_button)
    : NativeCheckboxGtk(radio_button) {
}

NativeRadioButtonGtk::~NativeRadioButtonGtk() {
}

RadioButton* NativeRadioButtonGtk::radio_button() {
  return static_cast<RadioButton*>(native_button_);
}

////////////////////////////////////////////////////////////////////////////////
// NativeRadioButtonGtk, NativeCheckboxGtk overrides:

void NativeRadioButtonGtk::CreateNativeControl() {
  GtkWidget* widget = gtk_radio_button_new(NULL);
  g_signal_connect(widget, "clicked",
                   G_CALLBACK(CallClicked), this);
  g_signal_connect(widget, "toggled",
                   G_CALLBACK(CallToggled), this);
  NativeControlCreated(widget);
}

void NativeRadioButtonGtk::OnToggled() {
  SyncCheckState();
}

// static
void NativeRadioButtonGtk::CallToggled(GtkButton* widget,
                                       NativeRadioButtonGtk* button) {
  button->OnToggled();
}

////////////////////////////////////////////////////////////////////////////////
// NativeRadioButtonGtk, NativeButtonWrapper overrides:
void NativeRadioButtonGtk::SetGroupFrom(NativeButtonWrapper* wrapper) {
  NativeRadioButtonGtk* peer = static_cast<NativeRadioButtonGtk*>(wrapper);
  GSList* group =
      gtk_radio_button_get_group(GTK_RADIO_BUTTON(peer->native_view()));
  // A group object is managed by gtk framework. It's updated as a radio
  // button is added to, or removed.
  DCHECK(group);
  GtkRadioButton* this_radio_button = GTK_RADIO_BUTTON(native_view());
  if (!g_slist_find(group, this_radio_button))
    gtk_radio_button_set_group(this_radio_button, group);
}

////////////////////////////////////////////////////////////////////////////////
// NativeRadioButtonGtk, NativeControlGtk overrides:
void NativeRadioButtonGtk::ViewHierarchyChanged(bool is_add,
                                                View *parent, View *child) {
  NativeControlGtk::ViewHierarchyChanged(is_add, parent, child);

  // look for the same group and update
  if (is_add && child == this) {
    View* container = GetParent();
    while (container && container->GetParent())
      container = container->GetParent();
    if (container) {
      std::vector<View*> other;
      container->GetViewsWithGroup(native_button_->GetGroup(), &other);
      for (std::vector<View*>::iterator i = other.begin();
           i != other.end();
           ++i) {
        if (*i != native_button_) {
          if ((*i)->GetClassName() != RadioButton::kViewClassName) {
            NOTREACHED() << "radio-button has same group as other non "
                "radio-button views.";
            continue;
          }
          // Join the group
          NativeButtonWrapper* wrapper =
              static_cast<RadioButton*>(*i)->native_wrapper();
          SetGroupFrom(wrapper);
          break;
        }
      }
    }

    // Sync the state after setting the group because single radio button
    // is always active.
    SyncCheckState();
  }
}

////////////////////////////////////////////////////////////////////////////////
// NativeButtonWrapper

// static
int NativeButtonWrapper::GetFixedWidth() {
  // TODO(brettw) implement this properly.
  return 10;
}

// static
NativeButtonWrapper* NativeButtonWrapper::CreateNativeButtonWrapper(
    NativeButton* native_button) {
  return new NativeButtonGtk(native_button);
}

// static
NativeButtonWrapper* NativeButtonWrapper::CreateCheckboxWrapper(
    Checkbox* checkbox) {
  return new NativeCheckboxGtk(checkbox);
}

// static
NativeButtonWrapper* NativeButtonWrapper::CreateRadioButtonWrapper(
    RadioButton* radio_button) {
  return new NativeRadioButtonGtk(radio_button);
}

}  // namespace views
<commit_msg>Fix a bug that caused a crash by NULL pointer dereference.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.

#include "views/controls/button/native_button_gtk.h"

#include <gtk/gtk.h>

#include <vector>

#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "views/controls/button/checkbox.h"
#include "views/controls/button/native_button.h"
#include "views/controls/button/radio_button.h"
#include "views/controls/native/native_view_host_gtk.h"
#include "views/widget/widget.h"

namespace views {

NativeButtonGtk::NativeButtonGtk(NativeButton* native_button)
    : native_button_(native_button) {
  // Associates the actual GtkWidget with the native_button so the native_button
  // is the one considered as having the focus (not the wrapper) when the
  // GtkWidget is focused directly (with a click for example).
  set_focus_view(native_button);
}

NativeButtonGtk::~NativeButtonGtk() {
}

void NativeButtonGtk::UpdateLabel() {
  if (!native_view())
    return;

  gtk_button_set_label(GTK_BUTTON(native_view()),
                       WideToUTF8(native_button_->label()).c_str());
  preferred_size_ = gfx::Size();
}

void NativeButtonGtk::UpdateFont() {
  if (!native_view())
    return;

  PangoFontDescription* pfd =
      gfx::Font::PangoFontFromGfxFont(native_button_->font());
  gtk_widget_modify_font(native_view(), pfd);
  pango_font_description_free(pfd);
  preferred_size_ = gfx::Size();
}

void NativeButtonGtk::UpdateEnabled() {
  SetEnabled(native_button_->IsEnabled());
}

void NativeButtonGtk::UpdateDefault() {
  if (!native_view())
    return;
  if (native_button_->is_default())
    gtk_widget_grab_default(native_view());
}

View* NativeButtonGtk::GetView() {
  return this;
}

void NativeButtonGtk::SetFocus() {
  // Focus the associated widget.
  Focus();
}

bool NativeButtonGtk::UsesNativeLabel() const {
  return true;
}

bool NativeButtonGtk::UsesNativeRadioButtonGroup() const {
  return true;
}

gfx::NativeView NativeButtonGtk::GetTestingHandle() const {
  return native_view();
}

gfx::Size NativeButtonGtk::GetPreferredSize() {
  if (!native_view())
    return gfx::Size();

  if (preferred_size_.IsEmpty()) {
    GtkRequisition size_request = { 0, 0 };
    gtk_widget_size_request(native_view(), &size_request);
    preferred_size_.SetSize(size_request.width, size_request.height);
  }
  return preferred_size_;
}

void NativeButtonGtk::CreateNativeControl() {
  GtkWidget* widget = gtk_button_new();
  g_signal_connect(widget, "clicked",
                   G_CALLBACK(CallClicked), this);

  // Any push button can become the default button.
  GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_DEFAULT);

  NativeControlCreated(widget);
}

void NativeButtonGtk::NativeControlCreated(GtkWidget* widget) {
  NativeControlGtk::NativeControlCreated(widget);

  UpdateFont();
  UpdateLabel();
  UpdateDefault();
}

// static
void NativeButtonGtk::CallClicked(GtkButton* widget, NativeButtonGtk* button) {
  button->OnClicked();
}

void NativeButtonGtk::OnClicked() {
  native_button_->ButtonPressed();
}

////////////////////////////////////////////////////////////////////////////////
// NativeCheckboxGtk
NativeCheckboxGtk::NativeCheckboxGtk(Checkbox* checkbox)
    : NativeButtonGtk(checkbox),
      deliver_click_event_(true) {
}

void NativeCheckboxGtk::SyncCheckState() {
  checkbox()->SetChecked(
      gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(native_view())));
}

Checkbox* NativeCheckboxGtk::checkbox() {
  return static_cast<Checkbox*>(native_button_);
}

void NativeCheckboxGtk::CreateNativeControl() {
  GtkWidget* widget = gtk_check_button_new();
  g_signal_connect(widget, "clicked",
                   G_CALLBACK(CallClicked), this);
  NativeControlCreated(widget);
}

void NativeCheckboxGtk::OnClicked() {
  // ignore event if the event is generated by
  // gtk_toggle_button_set_active below.
  if (deliver_click_event_) {
    SyncCheckState();
    NativeButtonGtk::OnClicked();
  }
}

void NativeCheckboxGtk::UpdateDefault() {
  if (!native_view())
    return;
  UpdateChecked();
}

void NativeCheckboxGtk::UpdateChecked() {
  if (!native_view())
    return;
  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(native_view()))
      != checkbox()->checked()) {
    // gtk_toggle_button_set_active emites "clicked" signal, which
    // invokes OnClicked method above. deliver_click_event_ flag is used
    // to prevent such signal to invoke OnClicked callback.
    deliver_click_event_ = false;
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(native_view()),
                                 checkbox()->checked());
    deliver_click_event_ = true;
  }
}

////////////////////////////////////////////////////////////////////////////////
NativeRadioButtonGtk::NativeRadioButtonGtk(RadioButton* radio_button)
    : NativeCheckboxGtk(radio_button) {
}

NativeRadioButtonGtk::~NativeRadioButtonGtk() {
}

RadioButton* NativeRadioButtonGtk::radio_button() {
  return static_cast<RadioButton*>(native_button_);
}

////////////////////////////////////////////////////////////////////////////////
// NativeRadioButtonGtk, NativeCheckboxGtk overrides:

void NativeRadioButtonGtk::CreateNativeControl() {
  GtkWidget* widget = gtk_radio_button_new(NULL);
  g_signal_connect(widget, "clicked",
                   G_CALLBACK(CallClicked), this);
  g_signal_connect(widget, "toggled",
                   G_CALLBACK(CallToggled), this);
  NativeControlCreated(widget);
}

void NativeRadioButtonGtk::OnToggled() {
  SyncCheckState();
}

// static
void NativeRadioButtonGtk::CallToggled(GtkButton* widget,
                                       NativeRadioButtonGtk* button) {
  button->OnToggled();
}

////////////////////////////////////////////////////////////////////////////////
// NativeRadioButtonGtk, NativeButtonWrapper overrides:
void NativeRadioButtonGtk::SetGroupFrom(NativeButtonWrapper* wrapper) {
  NativeRadioButtonGtk* peer = static_cast<NativeRadioButtonGtk*>(wrapper);
  GSList* group =
      gtk_radio_button_get_group(GTK_RADIO_BUTTON(peer->native_view()));
  // A group object is managed by gtk framework. It's updated as a radio
  // button is added to, or removed.
  DCHECK(group);
  GtkRadioButton* this_radio_button = GTK_RADIO_BUTTON(native_view());
  if (!g_slist_find(group, this_radio_button))
    gtk_radio_button_set_group(this_radio_button, group);
}

////////////////////////////////////////////////////////////////////////////////
// NativeRadioButtonGtk, NativeControlGtk overrides:
void NativeRadioButtonGtk::ViewHierarchyChanged(bool is_add,
                                                View *parent, View *child) {
  NativeControlGtk::ViewHierarchyChanged(is_add, parent, child);

  // look for the same group and update
  if (is_add && child == this) {
    View* container = GetParent();
    while (container && container->GetParent())
      container = container->GetParent();
    if (container) {
      std::vector<View*> other;
      container->GetViewsWithGroup(native_button_->GetGroup(), &other);
      for (std::vector<View*>::iterator i = other.begin();
           i != other.end();
           ++i) {
        if (*i != native_button_) {
          if ((*i)->GetClassName() != RadioButton::kViewClassName) {
            NOTREACHED() << "radio-button has same group as other non "
                "radio-button views.";
            continue;
          }
          // Join the group, if the peer's native wrapper is present.
          // A button without wrapper will be added to the group in
          // its own ViewHierachyChanged.
          NativeButtonWrapper* wrapper =
              static_cast<RadioButton*>(*i)->native_wrapper();
          if (wrapper) {
            SetGroupFrom(wrapper);
            break;
          }
        }
      }
    }

    // Sync the state after setting the group because single radio button
    // is always active.
    SyncCheckState();
  }
}

////////////////////////////////////////////////////////////////////////////////
// NativeButtonWrapper

// static
int NativeButtonWrapper::GetFixedWidth() {
  // TODO(brettw) implement this properly.
  return 10;
}

// static
NativeButtonWrapper* NativeButtonWrapper::CreateNativeButtonWrapper(
    NativeButton* native_button) {
  return new NativeButtonGtk(native_button);
}

// static
NativeButtonWrapper* NativeButtonWrapper::CreateCheckboxWrapper(
    Checkbox* checkbox) {
  return new NativeCheckboxGtk(checkbox);
}

// static
NativeButtonWrapper* NativeButtonWrapper::CreateRadioButtonWrapper(
    RadioButton* radio_button) {
  return new NativeRadioButtonGtk(radio_button);
}

}  // namespace views
<|endoftext|>


<commit_before>#include "pch.h"
#include "RoomScene.h"
#include "NetworkScene.h"
#include "TcpClient.h"
#include "MultiGameScene.h"
#include "WaitingLayer.h"

#define GET_ROOM_STATE_LABEL dynamic_cast<Label*>(this->getChildByName("RoomStateLabel"))

Scene* RoomScene::createScene()
{
    auto scene = Scene::create();
    auto layer = RoomScene::create();
    scene->addChild(layer, 0, "RoomScene");
    return scene;
}

bool RoomScene::init()
{
    if (!LayerColor::initWithColor(Color4B(0, 0, 128, 128)))
    {
        return false;
    }

    m_RoomID = -1;
    m_IsReady = false;
    auto winSize = Director::getInstance()->getWinSize();

    /////////////////////////////////////////////////캐릭터 초상화 추가할 부분/////////////////////////////////////////////
    /* Ready 캐릭터 띄울 얼굴추가 */
    MakeFaceSprite("Images/SelectFace/[Select]Magician.png", Vec2(winSize.width * 1 / 8, winSize.height * 3 / 4), Vec2(1.0f, 1.0f), Vec2(0, 1), HERO_MAGICIAN);
    MakeFaceSprite("Images/SelectFace/[Select]Jupiter.png", Vec2(winSize.width * 1 / 8, winSize.height * 3 / 4), Vec2(1.0f, 1.0f), Vec2(0, 1), HERO_JUPITER);
    MakeFaceSprite("Images/SelectFace/[Select]Laphinx.png", Vec2(winSize.width * 1 / 8, winSize.height * 3 / 4), Vec2(1.0f, 1.0f), Vec2(0, 1), HERO_LAPHINX);

    /* 캐릭터 선택창버튼 초상화 추가 (width 1/8씩 ++) */
    auto magicanFace = MenuItemImage::create("Images/SelectFace/[Select]Magician.png", "Images/SelectFace/[Select]Magician_selected.png", CC_CALLBACK_0(RoomScene::ClickMagician, this));
    SetFaceProperty(magicanFace, Vec2(winSize.width * 1 / 8, winSize.height * 1 / 4), Vec2(1.0f, 1.0f), Vec2(0, 1));
    auto jupiterFace = MenuItemImage::create("Images/SelectFace/[Select]Jupiter.png", "Images/SelectFace/[Select]Jupiter_selected.png", CC_CALLBACK_0(RoomScene::ClickJupiter, this));
    SetFaceProperty(jupiterFace, Vec2(winSize.width * 2 / 8, winSize.height * 1 / 4), Vec2(1.0f, 1.0f), Vec2(0, 1));
    auto laphinxFace = MenuItemImage::create("Images/SelectFace/[Select]Laphinx.png", "Images/SelectFace/[Select]Laphinx_selected.png", CC_CALLBACK_0(RoomScene::ClickLaphinx, this));
    SetFaceProperty(laphinxFace, Vec2(winSize.width * 3 / 8, winSize.height * 1 / 4), Vec2(1.0f, 1.0f), Vec2(0, 1));

    auto faceTable = Menu::create(magicanFace, jupiterFace,laphinxFace, NULL);
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    faceTable->setPosition(winSize.width * 1 / 8, winSize.height * 2 / 8);
    this->addChild(faceTable);

    m_CurHero = HERO_MAGICIAN;
    m_Facelist[HERO_MAGICIAN]->setVisible(true);

    auto readyButton = MenuItemImage::create("Images/GameReady.png", "Images/GameReady_selected.png", CC_CALLBACK_1(RoomScene::GameStartCallback, this));
    auto exitButton = MenuItemImage::create("Images/Gameout.png", "Images/Gameout_selected.png", CC_CALLBACK_1(RoomScene::GameExitCallback, this));
    exitButton->setPosition(winSize.width*1/8,winSize.height*-4/8);
    readyButton->setScale(0.8f, 0.8f);
    exitButton->setScale(0.7f, 0.7f);
    auto buttonMenu = Menu::create(readyButton, exitButton, NULL);
    buttonMenu->setPosition(winSize.width * 3 / 8, winSize.height * 11 / 16);
    this->addChild(buttonMenu);

    m_WaitingLayer = WaitingLayer::create();
    m_WaitingLayer->setVisible(false);
    this->addChild(m_WaitingLayer);

    auto label = Label::createWithSystemFont("연결 중...", "Thonburi", 50);
    label->setAnchorPoint(Vec2::ZERO);
    label->setHorizontalAlignment(TextHAlignment::CENTER);
    this->addChild(label, 0, "RoomStateLabel");

    // 1초 마다 Tick 함수를 호출한다.
    this->schedule(schedule_selector(RoomScene::Tick), 1.0f);
    return true;
}

void RoomScene::GameStartCallback(Ref* sender)	// 게임 시작
{
    if (TcpClient::getInstance()->checkSocket() == NULL || m_IsReady)
    {
        return;
    }
    m_IsReady = true;
    WaitingCheck();
    TcpClient::getInstance()->startGameRequest(m_RoomID,m_CurHero);
}

void RoomScene::GameExitCallback(Ref* sender)	// 나가기
{
    if (TcpClient::getInstance()->checkSocket() != NULL)
    {
        TcpClient::getInstance()->outRoomRequest(m_RoomID);
    }

    m_IsReady = false;
    WaitingCheck();
    Director::getInstance()->popScene();
}

//////////////////////////////////////////////////////////////////////////
void RoomScene::Tick(float dt)
{
    if (TcpClient::getInstance()->checkSocket() == NULL)
    {
        Director::getInstance()->popScene();
    }
    auto label = GET_ROOM_STATE_LABEL;
    if(label == nullptr)
        return;

    // 방 번호를 문자열로 변환 후 라벨에 적용
    char buf[32];
    _itoa(m_RoomID, buf, 32);
    std::string roomNum = buf;
    roomNum += "번 방";
    label->setString(roomNum.c_str());
}
//////////////////////////////////////////////////////////////////////////

void RoomScene::GameStartComplete()
{
    auto scene = MultiGameScene::createScene();

    auto layer = dynamic_cast<MultiGameScene*>(scene->getChildByName("MultiGameScene"));
    layer->SetRoomID(m_RoomID);

    m_IsReady = false;
    WaitingCheck();
    Director::getInstance()->pushScene(scene);
}

void RoomScene::WaitingCheck()
{
    if (m_IsReady == true)
    {
        m_WaitingLayer->setVisible(true);
    }
    else
    {
        m_WaitingLayer->setVisible(false);
    }
}

void RoomScene::MakeFaceSprite(const char* image, Vec2 pos, Vec2 scale, Vec2 anchor, HeroType hero)
{
    Sprite* sprite = Sprite::create(image);
    sprite->setPosition(pos);
    sprite->setScale(scale.x, scale.y);
    sprite->setAnchorPoint(anchor);
    sprite->setVisible(false);
    m_Facelist[hero] = sprite;
    this->addChild(sprite);
}

void RoomScene::SetFaceProperty(MenuItemImage* img, Vec2 pos, Vec2 scale, Vec2 anchor)
{
    img->setPosition(pos);
    img->setScale(scale.x, scale.y);
    img->setAnchorPoint(anchor);
}

void RoomScene::ChangeSelectedHero()
{
    switch (m_CurHero)
    {
    case HERO_MAGICIAN:
        for (auto& select : m_Facelist)
        {
            select.second->setVisible(false);
            if (select.first == HERO_MAGICIAN)
            {
                select.second->setVisible(true);
            }
        }
        break;
    case HERO_JUPITER:
        for (auto& select : m_Facelist)
        {
            select.second->setVisible(false);
            if (select.first == HERO_JUPITER)
            {
                select.second->setVisible(true);
            }
        }
    case HERO_LAPHINX:
        for (auto& select : m_Facelist)
        {
            select.second->setVisible(false);
            if (select.first == HERO_LAPHINX)
            {
                select.second->setVisible(true);
            }
        }
        break;
    case HERO_NONE:
        break;
    }
}

void RoomScene::ClickMagician()
{
    m_CurHero = HERO_MAGICIAN;
    ChangeSelectedHero();
}
void RoomScene::ClickJupiter()
{
    m_CurHero = HERO_JUPITER;
    ChangeSelectedHero();
}

void RoomScene::ClickLaphinx()
{
    m_CurHero = HERO_LAPHINX;
    ChangeSelectedHero();
}

<commit_msg>[C] 얼굴 제대로 바뀜<commit_after>#include "pch.h"
#include "RoomScene.h"
#include "NetworkScene.h"
#include "TcpClient.h"
#include "MultiGameScene.h"
#include "WaitingLayer.h"

#define GET_ROOM_STATE_LABEL dynamic_cast<Label*>(this->getChildByName("RoomStateLabel"))

Scene* RoomScene::createScene()
{
    auto scene = Scene::create();
    auto layer = RoomScene::create();
    scene->addChild(layer, 0, "RoomScene");
    return scene;
}

bool RoomScene::init()
{
    if (!LayerColor::initWithColor(Color4B(0, 0, 128, 128)))
    {
        return false;
    }

    m_RoomID = -1;
    m_IsReady = false;
    auto winSize = Director::getInstance()->getWinSize();

    /////////////////////////////////////////////////캐릭터 초상화 추가할 부분/////////////////////////////////////////////
    /* Ready 캐릭터 띄울 얼굴추가 */
    MakeFaceSprite("Images/SelectFace/[Select]Magician.png", Vec2(winSize.width * 1 / 8, winSize.height * 3 / 4), Vec2(1.0f, 1.0f), Vec2(0, 1), HERO_MAGICIAN);
    MakeFaceSprite("Images/SelectFace/[Select]Jupiter.png", Vec2(winSize.width * 1 / 8, winSize.height * 3 / 4), Vec2(1.0f, 1.0f), Vec2(0, 1), HERO_JUPITER);
    MakeFaceSprite("Images/SelectFace/[Select]Laphinx.png", Vec2(winSize.width * 1 / 8, winSize.height * 3 / 4), Vec2(1.0f, 1.0f), Vec2(0, 1), HERO_LAPHINX);

    /* 캐릭터 선택창버튼 초상화 추가 (width 1/8씩 ++) */
    auto magicanFace = MenuItemImage::create("Images/SelectFace/[Select]Magician.png", "Images/SelectFace/[Select]Magician_selected.png", CC_CALLBACK_0(RoomScene::ClickMagician, this));
    SetFaceProperty(magicanFace, Vec2(winSize.width * 1 / 8, winSize.height * 1 / 4), Vec2(1.0f, 1.0f), Vec2(0, 1));
    auto jupiterFace = MenuItemImage::create("Images/SelectFace/[Select]Jupiter.png", "Images/SelectFace/[Select]Jupiter_selected.png", CC_CALLBACK_0(RoomScene::ClickJupiter, this));
    SetFaceProperty(jupiterFace, Vec2(winSize.width * 2 / 8, winSize.height * 1 / 4), Vec2(1.0f, 1.0f), Vec2(0, 1));
    auto laphinxFace = MenuItemImage::create("Images/SelectFace/[Select]Laphinx.png", "Images/SelectFace/[Select]Laphinx_selected.png", CC_CALLBACK_0(RoomScene::ClickLaphinx, this));
    SetFaceProperty(laphinxFace, Vec2(winSize.width * 3 / 8, winSize.height * 1 / 4), Vec2(1.0f, 1.0f), Vec2(0, 1));

    auto faceTable = Menu::create(magicanFace, jupiterFace,laphinxFace, NULL);
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    faceTable->setPosition(winSize.width * 1 / 8, winSize.height * 2 / 8);
    this->addChild(faceTable);

    m_CurHero = HERO_MAGICIAN;
    m_Facelist[HERO_MAGICIAN]->setVisible(true);

    auto readyButton = MenuItemImage::create("Images/GameReady.png", "Images/GameReady_selected.png", CC_CALLBACK_1(RoomScene::GameStartCallback, this));
    auto exitButton = MenuItemImage::create("Images/Gameout.png", "Images/Gameout_selected.png", CC_CALLBACK_1(RoomScene::GameExitCallback, this));
    exitButton->setPosition(winSize.width*1/8,winSize.height*-4/8);
    readyButton->setScale(0.8f, 0.8f);
    exitButton->setScale(0.7f, 0.7f);
    auto buttonMenu = Menu::create(readyButton, exitButton, NULL);
    buttonMenu->setPosition(winSize.width * 3 / 8, winSize.height * 11 / 16);
    this->addChild(buttonMenu);

    m_WaitingLayer = WaitingLayer::create();
    m_WaitingLayer->setVisible(false);
    this->addChild(m_WaitingLayer);

    auto label = Label::createWithSystemFont("연결 중...", "Thonburi", 50);
    label->setAnchorPoint(Vec2::ZERO);
    label->setHorizontalAlignment(TextHAlignment::CENTER);
    this->addChild(label, 0, "RoomStateLabel");

    // 1초 마다 Tick 함수를 호출한다.
    this->schedule(schedule_selector(RoomScene::Tick), 1.0f);
    return true;
}

void RoomScene::GameStartCallback(Ref* sender)	// 게임 시작
{
    if (TcpClient::getInstance()->checkSocket() == NULL || m_IsReady)
    {
        return;
    }
    m_IsReady = true;
    WaitingCheck();
    TcpClient::getInstance()->startGameRequest(m_RoomID,m_CurHero);
}

void RoomScene::GameExitCallback(Ref* sender)	// 나가기
{
    if (TcpClient::getInstance()->checkSocket() != NULL)
    {
        TcpClient::getInstance()->outRoomRequest(m_RoomID);
    }

    m_IsReady = false;
    WaitingCheck();
    Director::getInstance()->popScene();
}

//////////////////////////////////////////////////////////////////////////
void RoomScene::Tick(float dt)
{
    if (TcpClient::getInstance()->checkSocket() == NULL)
    {
        Director::getInstance()->popScene();
    }
    auto label = GET_ROOM_STATE_LABEL;
    if(label == nullptr)
        return;

    // 방 번호를 문자열로 변환 후 라벨에 적용
    char buf[32];
    _itoa(m_RoomID, buf, 32);
    std::string roomNum = buf;
    roomNum += "번 방";
    label->setString(roomNum.c_str());
}
//////////////////////////////////////////////////////////////////////////

void RoomScene::GameStartComplete()
{
    auto scene = MultiGameScene::createScene();

    auto layer = dynamic_cast<MultiGameScene*>(scene->getChildByName("MultiGameScene"));
    layer->SetRoomID(m_RoomID);

    m_IsReady = false;
    WaitingCheck();
    Director::getInstance()->pushScene(scene);
}

void RoomScene::WaitingCheck()
{
    if (m_IsReady == true)
    {
        m_WaitingLayer->setVisible(true);
    }
    else
    {
        m_WaitingLayer->setVisible(false);
    }
}

void RoomScene::MakeFaceSprite(const char* image, Vec2 pos, Vec2 scale, Vec2 anchor, HeroType hero)
{
    Sprite* sprite = Sprite::create(image);
    sprite->setPosition(pos);
    sprite->setScale(scale.x, scale.y);
    sprite->setAnchorPoint(anchor);
    sprite->setVisible(false);
    m_Facelist[hero] = sprite;
    this->addChild(sprite);
}

void RoomScene::SetFaceProperty(MenuItemImage* img, Vec2 pos, Vec2 scale, Vec2 anchor)
{
    img->setPosition(pos);
    img->setScale(scale.x, scale.y);
    img->setAnchorPoint(anchor);
}

void RoomScene::ChangeSelectedHero()
{
    switch (m_CurHero)
    {
    case HERO_MAGICIAN:
        for (auto& select : m_Facelist)
        {
            select.second->setVisible(false);
            if (select.first == HERO_MAGICIAN)
            {
                select.second->setVisible(true);
            }
        }
        break;
    case HERO_JUPITER:
        for (auto& select : m_Facelist)
        {
            select.second->setVisible(false);
            if (select.first == HERO_JUPITER)
            {
                select.second->setVisible(true);
            }
        }
        break;
    case HERO_LAPHINX:
        for (auto& select : m_Facelist)
        {
            select.second->setVisible(false);
            if (select.first == HERO_LAPHINX)
            {
                select.second->setVisible(true);
            }
        }
        break;
    case HERO_NONE:
        break;
    }
}

void RoomScene::ClickMagician()
{
    m_CurHero = HERO_MAGICIAN;
    ChangeSelectedHero();
}
void RoomScene::ClickJupiter()
{
    m_CurHero = HERO_JUPITER;
    ChangeSelectedHero();
}

void RoomScene::ClickLaphinx()
{
    m_CurHero = HERO_LAPHINX;
    ChangeSelectedHero();
}

<|endoftext|>


<commit_before>//
// Copyright (c) 2018, University of Edinburgh
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//  * Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  * Neither the name of  nor the names of its contributors may be used to
//    endorse or promote products derived from this software without specific
//    prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#include <algorithm>
#include <limits>
#include <utility>

#include <exotica_core/planning_problem.h>
#include <exotica_core/server.h>
#include <exotica_core/setup.h>

#include <exotica_core/planning_problem_initializer.h>
#include <exotica_core/task_map_initializer.h>

namespace exotica
{
PlanningProblem::PlanningProblem() = default;
PlanningProblem::~PlanningProblem() = default;

std::string PlanningProblem::Print(const std::string& prepend) const
{
    std::string ret = Object::Print(prepend);
    ret += "\n" + prepend + "  Task definitions:";
    for (const auto& it : task_maps_)
        ret += "\n" + it.second->Print(prepend + "    ");
    return ret;
}

int PlanningProblem::get_num_positions() const
{
    return num_positions_;
}

int PlanningProblem::get_num_velocities() const
{
    return num_velocities_;
}

int PlanningProblem::get_num_controls() const
{
    return num_controls_;
}

Eigen::VectorXd PlanningProblem::ApplyStartState(bool update_traj)
{
    scene_->SetModelState(start_state_.head(num_positions_), t_start, update_traj);
    return scene_->GetControlledState();
}

void PlanningProblem::PreUpdate()
{
    for (auto& it : task_maps_) it.second->PreUpdate();
}

void PlanningProblem::SetStartState(Eigen::VectorXdRefConst x)
{
    const auto num_states = num_positions_ + num_velocities_;
    if (x.rows() == num_states)
    {
        start_state_ = x;
    }
    else if (x.rows() == scene_->GetKinematicTree().GetNumControlledJoints())
    {
        std::vector<std::string> jointNames = scene_->GetControlledJointNames();
        std::vector<std::string> modelNames = scene_->GetModelJointNames();
        for (int i = 0; i < jointNames.size(); ++i)
        {
            for (int j = 0; j < modelNames.size(); ++j)
            {
                if (jointNames[i] == modelNames[j]) start_state_[j] = x(i);
            }
        }
    }
    // TODO: Add support for num_controlled + tangent vector size initialisation
    else
    {
        ThrowNamed("Wrong start state vector size, expected " << num_states << ", got " << x.rows());
    }
}

Eigen::VectorXd PlanningProblem::GetStartState() const
{
    return start_state_;
}

void PlanningProblem::SetStartTime(double t)
{
    t_start = t;
}

double PlanningProblem::GetStartTime() const
{
    return t_start;
}

void PlanningProblem::InstantiateBase(const Initializer& init_in)
{
    Object::InstantiateObject(init_in);
    PlanningProblemInitializer init(init_in);

    task_maps_.clear();
    tasks_.clear();

    // Create the scene
    scene_.reset(new Scene());
    scene_->InstantiateInternal(SceneInitializer(init.PlanningScene));

    // Set size of positions. This is valid for kinematic problems and will be
    // overridden in dynamic problems to set num_velocities_ and num_controls_.
    num_positions_ = scene_->GetKinematicTree().GetNumModelJoints();
    N = scene_->GetKinematicTree().GetNumControlledJoints();

    // Check if dynamics solver has been initialised, and if so update problem
    // properties.
    if (scene_->GetDynamicsSolver() != nullptr)
    {
        // TODO: Strictly speaking N here should correspond to the number of controls, which comes from the dynamic solver - to be fixed!
        num_controls_ = scene_->GetDynamicsSolver()->get_num_controls();

        // TODO: As a current workaround, we assume num_velocities_ = num_positions_
        // This holds true if there are no special joints (including floating base
        // or spherical joints). For sanity, we check that the dynamics solver
        // dimensions match - otherwise throw.
        num_velocities_ = num_positions_;

        if (scene_->GetDynamicsSolver()->get_num_positions() != scene_->GetDynamicsSolver()->get_num_velocities())
        {
            // If the difference is exactly 1, just add it:
            // if ((scene_->GetDynamicsSolver()->get_num_positions() - scene_->GetDynamicsSolver()->get_num_velocities()) == 1)
            // {
            //     num_velocities_ -= 1;
            // }
            if (false)  // Deactivated for now (breaks Quadrotor, cf. #571)
            // Else, throw for now:
            else
            {
                WARNING_NAMED("PlanningProblem::InstantiateBase",
                              "Size of tangent vector in DynamicsSolver does not satisfy workaround-assumption (cf. #570):\n"
                                  << "num_positions_=" << num_positions_ << " vs (num_positions_=" << scene_->GetDynamicsSolver()->get_num_positions() << ", num_velocities_=" << scene_->GetDynamicsSolver()->get_num_velocities() << ").");
                ThrowPretty("SAD.");
            }
        }
    }

    // Set the start state
    start_state_ = Eigen::VectorXd::Zero(num_positions_ + num_velocities_);
    if (init.StartState.rows() > 0)
        SetStartState(init.StartState);

    // Set the start time
    if (init.StartTime < 0)
        ThrowNamed("Invalid start time " << init.StartTime);
    t_start = init.StartTime;

    // Set the derivative order for Kinematics
    switch (init.DerivativeOrder)
    {
        case 0:
            flags_ = KIN_FK;
            break;
        case 1:
            flags_ = KIN_FK | KIN_J;
            break;
        case 2:
            flags_ = KIN_FK | KIN_J | KIN_J_DOT;
            break;
    }

    KinematicsRequest request;
    request.flags = flags_;

    // Create the maps
    int id = 0;
    for (const Initializer& MapInitializer : init.Maps)
    {
        TaskMapPtr new_map = Setup::CreateMap(MapInitializer);
        new_map->AssignScene(scene_);
        new_map->ns_ = ns_ + "/" + new_map->GetObjectName();
        if (task_maps_.find(new_map->GetObjectName()) != task_maps_.end())
        {
            ThrowNamed("Map '" + new_map->GetObjectName() + "' already exists!");
        }
        std::vector<KinematicFrameRequest> frames = new_map->GetFrames();

        for (size_t i = 0; i < new_map->kinematics.size(); ++i)
            new_map->kinematics[i] = KinematicSolution(id, frames.size());
        id += frames.size();

        request.frames.insert(request.frames.end(), frames.begin(), frames.end());
        task_maps_[new_map->GetObjectName()] = new_map;
        tasks_.push_back(new_map);
    }
    scene_->RequestKinematics(request, std::bind(&PlanningProblem::UpdateTaskKinematics, this, std::placeholders::_1));

    id = 0;
    int idJ = 0;
    for (int i = 0; i < tasks_.size(); ++i)
    {
        tasks_[i]->id = i;
        tasks_[i]->start = id;
        tasks_[i]->length = tasks_[i]->TaskSpaceDim();
        tasks_[i]->start_jacobian = idJ;
        tasks_[i]->length_jacobian = tasks_[i]->TaskSpaceJacobianDim();
        id += tasks_[i]->length;
        idJ += tasks_[i]->length_jacobian;
    }

    if (init.Maps.size() == 0)
    {
        HIGHLIGHT("No maps were defined!");
    }
}

void PlanningProblem::UpdateTaskKinematics(std::shared_ptr<KinematicResponse> response)
{
    for (auto task : tasks_)
        task->kinematics[0].Create(response);
}

void PlanningProblem::UpdateMultipleTaskKinematics(std::vector<std::shared_ptr<KinematicResponse>> responses)
{
    for (auto task : tasks_)
    {
        if (task->kinematics.size() > responses.size())
        {
            ThrowNamed(responses.size() << " responses provided but task " << task->GetObjectName() << " requires " << task->kinematics.size());
        }

        for (size_t i = 0; i < task->kinematics.size(); ++i)
        {
            task->kinematics[i].Create(responses[i]);
        }
    }
}

TaskMapMap& PlanningProblem::GetTaskMaps()
{
    return task_maps_;
}

TaskMapVec& PlanningProblem::GetTasks()
{
    return tasks_;
}

ScenePtr PlanningProblem::GetScene() const
{
    return scene_;
}

std::pair<std::vector<double>, std::vector<double>> PlanningProblem::GetCostEvolution() const
{
    std::pair<std::vector<double>, std::vector<double>> ret;
    for (size_t position = 0; position < cost_evolution_.size(); ++position)
    {
        if (std::isnan(cost_evolution_[position].second)) break;
        double time_point = std::chrono::duration_cast<std::chrono::duration<double>>(cost_evolution_[position].first - cost_evolution_[0].first).count();
        ret.first.push_back(time_point);
        ret.second.push_back(cost_evolution_[position].second);
    }
    return ret;
}

double PlanningProblem::GetCostEvolution(int index) const
{
    if (index > -1 && index < cost_evolution_.size())
    {
        return cost_evolution_[index].second;
    }
    else if (index == -1)
    {
        return cost_evolution_[cost_evolution_.size() - 1].second;
    }
    else
    {
        ThrowPretty("Out of range");
    }
}

void PlanningProblem::ResetCostEvolution(size_t size)
{
    cost_evolution_.resize(size);
    cost_evolution_.assign(size, std::make_pair<std::chrono::high_resolution_clock::time_point, double>(std::chrono::high_resolution_clock::now(), std::numeric_limits<double>::quiet_NaN()));
}

void PlanningProblem::SetCostEvolution(int index, double value)
{
    if (index > -1 && index < cost_evolution_.size())
    {
        cost_evolution_[index].first = std::chrono::high_resolution_clock::now();
        cost_evolution_[index].second = value;
    }
    else if (index == -1)
    {
        cost_evolution_[cost_evolution_.size() - 1].first = std::chrono::high_resolution_clock::now();
        cost_evolution_[cost_evolution_.size() - 1].second = value;
    }
    else
    {
        ThrowPretty("Out of range: " << index << " where length=" << cost_evolution_.size());
    }
}
}  // namespace exotica
<commit_msg>[exotica_core] PlanningProblem: Fix compilation but keep floating-base dynamic problems deactivated - Relates to #571<commit_after>//
// Copyright (c) 2018, University of Edinburgh
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//  * Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  * Neither the name of  nor the names of its contributors may be used to
//    endorse or promote products derived from this software without specific
//    prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#include <algorithm>
#include <limits>
#include <utility>

#include <exotica_core/planning_problem.h>
#include <exotica_core/server.h>
#include <exotica_core/setup.h>

#include <exotica_core/planning_problem_initializer.h>
#include <exotica_core/task_map_initializer.h>

namespace exotica
{
PlanningProblem::PlanningProblem() = default;
PlanningProblem::~PlanningProblem() = default;

std::string PlanningProblem::Print(const std::string& prepend) const
{
    std::string ret = Object::Print(prepend);
    ret += "\n" + prepend + "  Task definitions:";
    for (const auto& it : task_maps_)
        ret += "\n" + it.second->Print(prepend + "    ");
    return ret;
}

int PlanningProblem::get_num_positions() const
{
    return num_positions_;
}

int PlanningProblem::get_num_velocities() const
{
    return num_velocities_;
}

int PlanningProblem::get_num_controls() const
{
    return num_controls_;
}

Eigen::VectorXd PlanningProblem::ApplyStartState(bool update_traj)
{
    scene_->SetModelState(start_state_.head(num_positions_), t_start, update_traj);
    return scene_->GetControlledState();
}

void PlanningProblem::PreUpdate()
{
    for (auto& it : task_maps_) it.second->PreUpdate();
}

void PlanningProblem::SetStartState(Eigen::VectorXdRefConst x)
{
    const auto num_states = num_positions_ + num_velocities_;
    if (x.rows() == num_states)
    {
        start_state_ = x;
    }
    else if (x.rows() == scene_->GetKinematicTree().GetNumControlledJoints())
    {
        std::vector<std::string> jointNames = scene_->GetControlledJointNames();
        std::vector<std::string> modelNames = scene_->GetModelJointNames();
        for (int i = 0; i < jointNames.size(); ++i)
        {
            for (int j = 0; j < modelNames.size(); ++j)
            {
                if (jointNames[i] == modelNames[j]) start_state_[j] = x(i);
            }
        }
    }
    // TODO: Add support for num_controlled + tangent vector size initialisation
    else
    {
        ThrowNamed("Wrong start state vector size, expected " << num_states << ", got " << x.rows());
    }
}

Eigen::VectorXd PlanningProblem::GetStartState() const
{
    return start_state_;
}

void PlanningProblem::SetStartTime(double t)
{
    t_start = t;
}

double PlanningProblem::GetStartTime() const
{
    return t_start;
}

void PlanningProblem::InstantiateBase(const Initializer& init_in)
{
    Object::InstantiateObject(init_in);
    PlanningProblemInitializer init(init_in);

    task_maps_.clear();
    tasks_.clear();

    // Create the scene
    scene_.reset(new Scene());
    scene_->InstantiateInternal(SceneInitializer(init.PlanningScene));

    // Set size of positions. This is valid for kinematic problems and will be
    // overridden in dynamic problems to set num_velocities_ and num_controls_.
    num_positions_ = scene_->GetKinematicTree().GetNumModelJoints();
    N = scene_->GetKinematicTree().GetNumControlledJoints();

    // Check if dynamics solver has been initialised, and if so update problem
    // properties.
    if (scene_->GetDynamicsSolver() != nullptr)
    {
        // TODO: Strictly speaking N here should correspond to the number of controls, which comes from the dynamic solver - to be fixed!
        num_controls_ = scene_->GetDynamicsSolver()->get_num_controls();

        // TODO: As a current workaround, we assume num_velocities_ = num_positions_
        // This holds true if there are no special joints (including floating base
        // or spherical joints). For sanity, we check that the dynamics solver
        // dimensions match - otherwise throw.
        num_velocities_ = num_positions_;

        if ((scene_->GetDynamicsSolver()->get_num_positions() != scene_->GetDynamicsSolver()->get_num_velocities()) ||
            (scene_->GetDynamicsSolver()->get_num_positions() != num_positions_))
        {
            // The quadrotor and other floating-base robots are currently broken (cf. #571)
            if (scene_->GetDynamicsSolver()->get_num_positions() > num_positions_)
            {
                ThrowPretty("Proper floating-base joints in dynamic problems not yet supported. Cf. #571.");
                // num_positions_ = scene_->GetDynamicsSolver()->get_num_positions();
                // num_velocities_ = scene_->GetDynamicsSolver()->get_num_velocities();
            }
            // If the difference is exactly 1, just add it:
            else if ((scene_->GetDynamicsSolver()->get_num_positions() - scene_->GetDynamicsSolver()->get_num_velocities()) == 1)
            {
                num_velocities_ -= 1;
            }
            // Else, throw for now:
            else
            {
                WARNING_NAMED("PlanningProblem::InstantiateBase",
                              "Size of tangent vector in DynamicsSolver does not satisfy workaround-assumption (cf. #570):\n"
                                  << "num_positions_=" << num_positions_ << " vs (num_positions_=" << scene_->GetDynamicsSolver()->get_num_positions() << ", num_velocities_=" << scene_->GetDynamicsSolver()->get_num_velocities() << ").");
                ThrowPretty("SAD.");
            }
        }
    }

    // Set the start state
    start_state_ = Eigen::VectorXd::Zero(num_positions_ + num_velocities_);
    if (init.StartState.rows() > 0)
        SetStartState(init.StartState);

    // Set the start time
    if (init.StartTime < 0)
        ThrowNamed("Invalid start time " << init.StartTime);
    t_start = init.StartTime;

    // Set the derivative order for Kinematics
    switch (init.DerivativeOrder)
    {
        case 0:
            flags_ = KIN_FK;
            break;
        case 1:
            flags_ = KIN_FK | KIN_J;
            break;
        case 2:
            flags_ = KIN_FK | KIN_J | KIN_J_DOT;
            break;
    }

    KinematicsRequest request;
    request.flags = flags_;

    // Create the maps
    int id = 0;
    for (const Initializer& MapInitializer : init.Maps)
    {
        TaskMapPtr new_map = Setup::CreateMap(MapInitializer);
        new_map->AssignScene(scene_);
        new_map->ns_ = ns_ + "/" + new_map->GetObjectName();
        if (task_maps_.find(new_map->GetObjectName()) != task_maps_.end())
        {
            ThrowNamed("Map '" + new_map->GetObjectName() + "' already exists!");
        }
        std::vector<KinematicFrameRequest> frames = new_map->GetFrames();

        for (size_t i = 0; i < new_map->kinematics.size(); ++i)
            new_map->kinematics[i] = KinematicSolution(id, frames.size());
        id += frames.size();

        request.frames.insert(request.frames.end(), frames.begin(), frames.end());
        task_maps_[new_map->GetObjectName()] = new_map;
        tasks_.push_back(new_map);
    }
    scene_->RequestKinematics(request, std::bind(&PlanningProblem::UpdateTaskKinematics, this, std::placeholders::_1));

    id = 0;
    int idJ = 0;
    for (int i = 0; i < tasks_.size(); ++i)
    {
        tasks_[i]->id = i;
        tasks_[i]->start = id;
        tasks_[i]->length = tasks_[i]->TaskSpaceDim();
        tasks_[i]->start_jacobian = idJ;
        tasks_[i]->length_jacobian = tasks_[i]->TaskSpaceJacobianDim();
        id += tasks_[i]->length;
        idJ += tasks_[i]->length_jacobian;
    }

    if (init.Maps.size() == 0)
    {
        HIGHLIGHT("No maps were defined!");
    }
}

void PlanningProblem::UpdateTaskKinematics(std::shared_ptr<KinematicResponse> response)
{
    for (auto task : tasks_)
        task->kinematics[0].Create(response);
}

void PlanningProblem::UpdateMultipleTaskKinematics(std::vector<std::shared_ptr<KinematicResponse>> responses)
{
    for (auto task : tasks_)
    {
        if (task->kinematics.size() > responses.size())
        {
            ThrowNamed(responses.size() << " responses provided but task " << task->GetObjectName() << " requires " << task->kinematics.size());
        }

        for (size_t i = 0; i < task->kinematics.size(); ++i)
        {
            task->kinematics[i].Create(responses[i]);
        }
    }
}

TaskMapMap& PlanningProblem::GetTaskMaps()
{
    return task_maps_;
}

TaskMapVec& PlanningProblem::GetTasks()
{
    return tasks_;
}

ScenePtr PlanningProblem::GetScene() const
{
    return scene_;
}

std::pair<std::vector<double>, std::vector<double>> PlanningProblem::GetCostEvolution() const
{
    std::pair<std::vector<double>, std::vector<double>> ret;
    for (size_t position = 0; position < cost_evolution_.size(); ++position)
    {
        if (std::isnan(cost_evolution_[position].second)) break;
        double time_point = std::chrono::duration_cast<std::chrono::duration<double>>(cost_evolution_[position].first - cost_evolution_[0].first).count();
        ret.first.push_back(time_point);
        ret.second.push_back(cost_evolution_[position].second);
    }
    return ret;
}

double PlanningProblem::GetCostEvolution(int index) const
{
    if (index > -1 && index < cost_evolution_.size())
    {
        return cost_evolution_[index].second;
    }
    else if (index == -1)
    {
        return cost_evolution_[cost_evolution_.size() - 1].second;
    }
    else
    {
        ThrowPretty("Out of range");
    }
}

void PlanningProblem::ResetCostEvolution(size_t size)
{
    cost_evolution_.resize(size);
    cost_evolution_.assign(size, std::make_pair<std::chrono::high_resolution_clock::time_point, double>(std::chrono::high_resolution_clock::now(), std::numeric_limits<double>::quiet_NaN()));
}

void PlanningProblem::SetCostEvolution(int index, double value)
{
    if (index > -1 && index < cost_evolution_.size())
    {
        cost_evolution_[index].first = std::chrono::high_resolution_clock::now();
        cost_evolution_[index].second = value;
    }
    else if (index == -1)
    {
        cost_evolution_[cost_evolution_.size() - 1].first = std::chrono::high_resolution_clock::now();
        cost_evolution_[cost_evolution_.size() - 1].second = value;
    }
    else
    {
        ThrowPretty("Out of range: " << index << " where length=" << cost_evolution_.size());
    }
}
}  // namespace exotica
<|endoftext|>