<commit_before>//===--- Quality.cpp --------------------------------------------*- C++-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===---------------------------------------------------------------------===//
#include "Quality.h"
#include "FileDistance.h"
#include "URI.h"
#include "index/Index.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <cmath>

namespace clang {
namespace clangd {
using namespace llvm;
static bool IsReserved(StringRef Name) {
  // FIXME: Should we exclude _Bool and others recognized by the standard?
  return Name.size() >= 2 && Name[0] == '_' &&
         (isUppercase(Name[1]) || Name[1] == '_');
}

static bool hasDeclInMainFile(const Decl &D) {
  auto &SourceMgr = D.getASTContext().getSourceManager();
  for (auto *Redecl : D.redecls()) {
    auto Loc = SourceMgr.getSpellingLoc(Redecl->getLocation());
    if (SourceMgr.isWrittenInMainFile(Loc))
      return true;
  }
  return false;
}

static SymbolQualitySignals::SymbolCategory categorize(const NamedDecl &ND) {
  class Switch
      : public ConstDeclVisitor<Switch, SymbolQualitySignals::SymbolCategory> {
  public:
#define MAP(DeclType, Category)                                                \
  SymbolQualitySignals::SymbolCategory Visit##DeclType(const DeclType *) {     \
    return SymbolQualitySignals::Category;                                     \
  }
    MAP(NamespaceDecl, Namespace);
    MAP(NamespaceAliasDecl, Namespace);
    MAP(TypeDecl, Type);
    MAP(TypeAliasTemplateDecl, Type);
    MAP(ClassTemplateDecl, Type);
    MAP(ValueDecl, Variable);
    MAP(VarTemplateDecl, Variable);
    MAP(FunctionDecl, Function);
    MAP(FunctionTemplateDecl, Function);
    MAP(Decl, Unknown);
#undef MAP
  };
  return Switch().Visit(&ND);
}

static SymbolQualitySignals::SymbolCategory categorize(const CodeCompletionResult &R) {
  if (R.Declaration)
    return categorize(*R.Declaration);
  if (R.Kind == CodeCompletionResult::RK_Macro)
    return SymbolQualitySignals::Macro;
  // Everything else is a keyword or a pattern. Patterns are mostly keywords
  // too, except a few which we recognize by cursor kind.
  switch (R.CursorKind) {
    case CXCursor_CXXMethod:
      return SymbolQualitySignals::Function;
    case CXCursor_ModuleImportDecl:
      return SymbolQualitySignals::Namespace;
    case CXCursor_MacroDefinition:
      return SymbolQualitySignals::Macro;
    case CXCursor_TypeRef:
      return SymbolQualitySignals::Type;
    case CXCursor_MemberRef:
      return SymbolQualitySignals::Variable;
    default:
      return SymbolQualitySignals::Keyword;
  }
}

static SymbolQualitySignals::SymbolCategory
categorize(const index::SymbolInfo &D) {
  switch (D.Kind) {
    case index::SymbolKind::Namespace:
    case index::SymbolKind::NamespaceAlias:
      return SymbolQualitySignals::Namespace;
    case index::SymbolKind::Macro:
      return SymbolQualitySignals::Macro;
    case index::SymbolKind::Enum:
    case index::SymbolKind::Struct:
    case index::SymbolKind::Class:
    case index::SymbolKind::Protocol:
    case index::SymbolKind::Extension:
    case index::SymbolKind::Union:
    case index::SymbolKind::TypeAlias:
      return SymbolQualitySignals::Type;
    case index::SymbolKind::Function:
    case index::SymbolKind::ClassMethod:
    case index::SymbolKind::InstanceMethod:
    case index::SymbolKind::StaticMethod:
    case index::SymbolKind::InstanceProperty:
    case index::SymbolKind::ClassProperty:
    case index::SymbolKind::StaticProperty:
    case index::SymbolKind::Constructor:
    case index::SymbolKind::Destructor:
    case index::SymbolKind::ConversionFunction:
      return SymbolQualitySignals::Function;
    case index::SymbolKind::Variable:
    case index::SymbolKind::Field:
    case index::SymbolKind::EnumConstant:
    case index::SymbolKind::Parameter:
      return SymbolQualitySignals::Variable;
    case index::SymbolKind::Using:
    case index::SymbolKind::Module:
    case index::SymbolKind::Unknown:
      return SymbolQualitySignals::Unknown;
  }
  llvm_unreachable("Unknown index::SymbolKind");
}

void SymbolQualitySignals::merge(const CodeCompletionResult &SemaCCResult) {
  if (SemaCCResult.Availability == CXAvailability_Deprecated)
    Deprecated = true;

  Category = categorize(SemaCCResult);

  if (SemaCCResult.Declaration) {
    if (auto *ID = SemaCCResult.Declaration->getIdentifier())
      ReservedName = ReservedName || IsReserved(ID->getName());
  } else if (SemaCCResult.Kind == CodeCompletionResult::RK_Macro)
    ReservedName = ReservedName || IsReserved(SemaCCResult.Macro->getName());
}

void SymbolQualitySignals::merge(const Symbol &IndexResult) {
  References = std::max(IndexResult.References, References);
  Category = categorize(IndexResult.SymInfo);
  ReservedName = ReservedName || IsReserved(IndexResult.Name);
}

float SymbolQualitySignals::evaluate() const {
  float Score = 1;

  // This avoids a sharp gradient for tail symbols, and also neatly avoids the
  // question of whether 0 references means a bad symbol or missing data.
  if (References >= 10)
    Score *= std::log10(References);

  if (Deprecated)
    Score *= 0.1f;
  if (ReservedName)
    Score *= 0.1f;

  switch (Category) {
    case Keyword:  // Often relevant, but misses most signals.
      Score *= 4;  // FIXME: important keywords should have specific boosts.
      break;
    case Type:
    case Function:
    case Variable:
      Score *= 1.1f;
      break;
    case Namespace:
      Score *= 0.8f;
      break;
    case Macro:
      Score *= 0.2f;
      break;
    case Unknown:
      break;
  }

  return Score;
}

raw_ostream &operator<<(raw_ostream &OS, const SymbolQualitySignals &S) {
  OS << formatv("=== Symbol quality: {0}\n", S.evaluate());
  OS << formatv("\tReferences: {0}\n", S.References);
  OS << formatv("\tDeprecated: {0}\n", S.Deprecated);
  OS << formatv("\tReserved name: {0}\n", S.ReservedName);
  OS << formatv("\tCategory: {0}\n", static_cast<int>(S.Category));
  return OS;
}

static SymbolRelevanceSignals::AccessibleScope
ComputeScope(const NamedDecl *D) {
  // Injected "Foo" within the class "Foo" has file scope, not class scope.
  const DeclContext *DC = D->getDeclContext();
  if (auto *R = dyn_cast_or_null<RecordDecl>(D))
    if (R->isInjectedClassName())
      DC = DC->getParent();
  // Class constructor should have the same scope as the class.
  if (isa<CXXConstructorDecl>(D))
    DC = DC->getParent();
  bool InClass = false;
  for (; !DC->isFileContext(); DC = DC->getParent()) {
    if (DC->isFunctionOrMethod())
      return SymbolRelevanceSignals::FunctionScope;
    InClass = InClass || DC->isRecord();
  }
  if (InClass)
    return SymbolRelevanceSignals::ClassScope;
  // This threshold could be tweaked, e.g. to treat module-visible as global.
  if (D->getLinkageInternal() < ExternalLinkage)
    return SymbolRelevanceSignals::FileScope;
  return SymbolRelevanceSignals::GlobalScope;
}

void SymbolRelevanceSignals::merge(const Symbol &IndexResult) {
  // FIXME: Index results always assumed to be at global scope. If Scope becomes
  // relevant to non-completion requests, we should recognize class members etc.

  SymbolURI = IndexResult.CanonicalDeclaration.FileURI;
}

void SymbolRelevanceSignals::merge(const CodeCompletionResult &SemaCCResult) {
  if (SemaCCResult.Availability == CXAvailability_NotAvailable ||
      SemaCCResult.Availability == CXAvailability_NotAccessible)
    Forbidden = true;

  if (SemaCCResult.Declaration) {
    // We boost things that have decls in the main file. We give a fixed score
    // for all other declarations in sema as they are already included in the
    // translation unit.
    float DeclProximity =
        hasDeclInMainFile(*SemaCCResult.Declaration) ? 1.0 : 0.6;
    SemaProximityScore = std::max(DeclProximity, SemaProximityScore);
  }

  // Declarations are scoped, others (like macros) are assumed global.
  if (SemaCCResult.Declaration)
    Scope = std::min(Scope, ComputeScope(SemaCCResult.Declaration));
}

static std::pair<float, unsigned> proximityScore(llvm::StringRef SymbolURI,
                                                 URIDistance *D) {
  if (!D || SymbolURI.empty())
    return {0.f, 0u};
  unsigned Distance = D->distance(SymbolURI);
  // Assume approximately default options are used for sensible scoring.
  return {std::exp(Distance * -0.4f / FileDistanceOptions().UpCost), Distance};
}

float SymbolRelevanceSignals::evaluate() const {
  float Score = 1;

  if (Forbidden)
    return 0;

  Score *= NameMatch;

  // Proximity scores are [0,1] and we translate them into a multiplier in the
  // range from 1 to 3.
  Score *= 1 + 2 * std::max(proximityScore(SymbolURI, FileProximityMatch).first,
                            SemaProximityScore);

  // Symbols like local variables may only be referenced within their scope.
  // Conversely if we're in that scope, it's likely we'll reference them.
  if (Query == CodeComplete) {
    // The narrower the scope where a symbol is visible, the more likely it is
    // to be relevant when it is available.
    switch (Scope) {
    case GlobalScope:
      break;
    case FileScope:
      Score *= 1.5;
      break;
    case ClassScope:
      Score *= 2;
      break;
    case FunctionScope:
      Score *= 4;
      break;
    }
  }

  return Score;
}

raw_ostream &operator<<(raw_ostream &OS, const SymbolRelevanceSignals &S) {
  OS << formatv("=== Symbol relevance: {0}\n", S.evaluate());
  OS << formatv("\tName match: {0}\n", S.NameMatch);
  OS << formatv("\tForbidden: {0}\n", S.Forbidden);
  OS << formatv("\tSymbol URI: {0}\n", S.SymbolURI);
  if (S.FileProximityMatch) {
    auto Score = proximityScore(S.SymbolURI, S.FileProximityMatch);
    OS << formatv("\tIndex proximity: {0} (distance={1})\n", Score.first,
                  Score.second);
  }
  OS << formatv("\tSema proximity: {0}\n", S.SemaProximityScore);
  OS << formatv("\tQuery type: {0}\n", static_cast<int>(S.Query));
  OS << formatv("\tScope: {0}\n", static_cast<int>(S.Scope));
  return OS;
}

float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance) {
  return SymbolQuality * SymbolRelevance;
}

// Produces an integer that sorts in the same order as F.
// That is: a < b <==> encodeFloat(a) < encodeFloat(b).
static uint32_t encodeFloat(float F) {
  static_assert(std::numeric_limits<float>::is_iec559, "");
  constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1);

  // Get the bits of the float. Endianness is the same as for integers.
  uint32_t U = FloatToBits(F);
  // IEEE 754 floats compare like sign-magnitude integers.
  if (U & TopBit)    // Negative float.
    return 0 - U;    // Map onto the low half of integers, order reversed.
  return U + TopBit; // Positive floats map onto the high half of integers.
}

std::string sortText(float Score, llvm::StringRef Name) {
  // We convert -Score to an integer, and hex-encode for readability.
  // Example: [0.5, "foo"] -> "41000000foo"
  std::string S;
  llvm::raw_string_ostream OS(S);
  write_hex(OS, encodeFloat(-Score), llvm::HexPrintStyle::Lower,
            /*Width=*/2 * sizeof(Score));
  OS << Name;
  OS.flush();
  return S;
}

} // namespace clangd
} // namespace clang
<commit_msg>[NFS] Wipe trailing whitespaces<commit_after>//===--- Quality.cpp --------------------------------------------*- C++-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===---------------------------------------------------------------------===//
#include "Quality.h"
#include "FileDistance.h"
#include "URI.h"
#include "index/Index.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <cmath>

namespace clang {
namespace clangd {
using namespace llvm;
static bool IsReserved(StringRef Name) {
  // FIXME: Should we exclude _Bool and others recognized by the standard?
  return Name.size() >= 2 && Name[0] == '_' &&
         (isUppercase(Name[1]) || Name[1] == '_');
}

static bool hasDeclInMainFile(const Decl &D) {
  auto &SourceMgr = D.getASTContext().getSourceManager();
  for (auto *Redecl : D.redecls()) {
    auto Loc = SourceMgr.getSpellingLoc(Redecl->getLocation());
    if (SourceMgr.isWrittenInMainFile(Loc))
      return true;
  }
  return false;
}

static SymbolQualitySignals::SymbolCategory categorize(const NamedDecl &ND) {
  class Switch
      : public ConstDeclVisitor<Switch, SymbolQualitySignals::SymbolCategory> {
  public:
#define MAP(DeclType, Category)                                                \
  SymbolQualitySignals::SymbolCategory Visit##DeclType(const DeclType *) {     \
    return SymbolQualitySignals::Category;                                     \
  }
    MAP(NamespaceDecl, Namespace);
    MAP(NamespaceAliasDecl, Namespace);
    MAP(TypeDecl, Type);
    MAP(TypeAliasTemplateDecl, Type);
    MAP(ClassTemplateDecl, Type);
    MAP(ValueDecl, Variable);
    MAP(VarTemplateDecl, Variable);
    MAP(FunctionDecl, Function);
    MAP(FunctionTemplateDecl, Function);
    MAP(Decl, Unknown);
#undef MAP
  };
  return Switch().Visit(&ND);
}

static SymbolQualitySignals::SymbolCategory
categorize(const CodeCompletionResult &R) {
  if (R.Declaration)
    return categorize(*R.Declaration);
  if (R.Kind == CodeCompletionResult::RK_Macro)
    return SymbolQualitySignals::Macro;
  // Everything else is a keyword or a pattern. Patterns are mostly keywords
  // too, except a few which we recognize by cursor kind.
  switch (R.CursorKind) {
  case CXCursor_CXXMethod:
    return SymbolQualitySignals::Function;
  case CXCursor_ModuleImportDecl:
    return SymbolQualitySignals::Namespace;
  case CXCursor_MacroDefinition:
    return SymbolQualitySignals::Macro;
  case CXCursor_TypeRef:
    return SymbolQualitySignals::Type;
  case CXCursor_MemberRef:
    return SymbolQualitySignals::Variable;
  default:
    return SymbolQualitySignals::Keyword;
  }
}

static SymbolQualitySignals::SymbolCategory
categorize(const index::SymbolInfo &D) {
  switch (D.Kind) {
  case index::SymbolKind::Namespace:
  case index::SymbolKind::NamespaceAlias:
    return SymbolQualitySignals::Namespace;
  case index::SymbolKind::Macro:
    return SymbolQualitySignals::Macro;
  case index::SymbolKind::Enum:
  case index::SymbolKind::Struct:
  case index::SymbolKind::Class:
  case index::SymbolKind::Protocol:
  case index::SymbolKind::Extension:
  case index::SymbolKind::Union:
  case index::SymbolKind::TypeAlias:
    return SymbolQualitySignals::Type;
  case index::SymbolKind::Function:
  case index::SymbolKind::ClassMethod:
  case index::SymbolKind::InstanceMethod:
  case index::SymbolKind::StaticMethod:
  case index::SymbolKind::InstanceProperty:
  case index::SymbolKind::ClassProperty:
  case index::SymbolKind::StaticProperty:
  case index::SymbolKind::Constructor:
  case index::SymbolKind::Destructor:
  case index::SymbolKind::ConversionFunction:
    return SymbolQualitySignals::Function;
  case index::SymbolKind::Variable:
  case index::SymbolKind::Field:
  case index::SymbolKind::EnumConstant:
  case index::SymbolKind::Parameter:
    return SymbolQualitySignals::Variable;
  case index::SymbolKind::Using:
  case index::SymbolKind::Module:
  case index::SymbolKind::Unknown:
    return SymbolQualitySignals::Unknown;
  }
  llvm_unreachable("Unknown index::SymbolKind");
}

void SymbolQualitySignals::merge(const CodeCompletionResult &SemaCCResult) {
  if (SemaCCResult.Availability == CXAvailability_Deprecated)
    Deprecated = true;

  Category = categorize(SemaCCResult);

  if (SemaCCResult.Declaration) {
    if (auto *ID = SemaCCResult.Declaration->getIdentifier())
      ReservedName = ReservedName || IsReserved(ID->getName());
  } else if (SemaCCResult.Kind == CodeCompletionResult::RK_Macro)
    ReservedName = ReservedName || IsReserved(SemaCCResult.Macro->getName());
}

void SymbolQualitySignals::merge(const Symbol &IndexResult) {
  References = std::max(IndexResult.References, References);
  Category = categorize(IndexResult.SymInfo);
  ReservedName = ReservedName || IsReserved(IndexResult.Name);
}

float SymbolQualitySignals::evaluate() const {
  float Score = 1;

  // This avoids a sharp gradient for tail symbols, and also neatly avoids the
  // question of whether 0 references means a bad symbol or missing data.
  if (References >= 10)
    Score *= std::log10(References);

  if (Deprecated)
    Score *= 0.1f;
  if (ReservedName)
    Score *= 0.1f;

  switch (Category) {
  case Keyword: // Often relevant, but misses most signals.
    Score *= 4; // FIXME: important keywords should have specific boosts.
    break;
  case Type:
  case Function:
  case Variable:
    Score *= 1.1f;
    break;
  case Namespace:
    Score *= 0.8f;
    break;
  case Macro:
    Score *= 0.2f;
    break;
  case Unknown:
    break;
  }

  return Score;
}

raw_ostream &operator<<(raw_ostream &OS, const SymbolQualitySignals &S) {
  OS << formatv("=== Symbol quality: {0}\n", S.evaluate());
  OS << formatv("\tReferences: {0}\n", S.References);
  OS << formatv("\tDeprecated: {0}\n", S.Deprecated);
  OS << formatv("\tReserved name: {0}\n", S.ReservedName);
  OS << formatv("\tCategory: {0}\n", static_cast<int>(S.Category));
  return OS;
}

static SymbolRelevanceSignals::AccessibleScope
ComputeScope(const NamedDecl *D) {
  // Injected "Foo" within the class "Foo" has file scope, not class scope.
  const DeclContext *DC = D->getDeclContext();
  if (auto *R = dyn_cast_or_null<RecordDecl>(D))
    if (R->isInjectedClassName())
      DC = DC->getParent();
  // Class constructor should have the same scope as the class.
  if (isa<CXXConstructorDecl>(D))
    DC = DC->getParent();
  bool InClass = false;
  for (; !DC->isFileContext(); DC = DC->getParent()) {
    if (DC->isFunctionOrMethod())
      return SymbolRelevanceSignals::FunctionScope;
    InClass = InClass || DC->isRecord();
  }
  if (InClass)
    return SymbolRelevanceSignals::ClassScope;
  // This threshold could be tweaked, e.g. to treat module-visible as global.
  if (D->getLinkageInternal() < ExternalLinkage)
    return SymbolRelevanceSignals::FileScope;
  return SymbolRelevanceSignals::GlobalScope;
}

void SymbolRelevanceSignals::merge(const Symbol &IndexResult) {
  // FIXME: Index results always assumed to be at global scope. If Scope becomes
  // relevant to non-completion requests, we should recognize class members etc.

  SymbolURI = IndexResult.CanonicalDeclaration.FileURI;
}

void SymbolRelevanceSignals::merge(const CodeCompletionResult &SemaCCResult) {
  if (SemaCCResult.Availability == CXAvailability_NotAvailable ||
      SemaCCResult.Availability == CXAvailability_NotAccessible)
    Forbidden = true;

  if (SemaCCResult.Declaration) {
    // We boost things that have decls in the main file. We give a fixed score
    // for all other declarations in sema as they are already included in the
    // translation unit.
    float DeclProximity =
        hasDeclInMainFile(*SemaCCResult.Declaration) ? 1.0 : 0.6;
    SemaProximityScore = std::max(DeclProximity, SemaProximityScore);
  }

  // Declarations are scoped, others (like macros) are assumed global.
  if (SemaCCResult.Declaration)
    Scope = std::min(Scope, ComputeScope(SemaCCResult.Declaration));
}

static std::pair<float, unsigned> proximityScore(llvm::StringRef SymbolURI,
                                                 URIDistance *D) {
  if (!D || SymbolURI.empty())
    return {0.f, 0u};
  unsigned Distance = D->distance(SymbolURI);
  // Assume approximately default options are used for sensible scoring.
  return {std::exp(Distance * -0.4f / FileDistanceOptions().UpCost), Distance};
}

float SymbolRelevanceSignals::evaluate() const {
  float Score = 1;

  if (Forbidden)
    return 0;

  Score *= NameMatch;

  // Proximity scores are [0,1] and we translate them into a multiplier in the
  // range from 1 to 3.
  Score *= 1 + 2 * std::max(proximityScore(SymbolURI, FileProximityMatch).first,
                            SemaProximityScore);

  // Symbols like local variables may only be referenced within their scope.
  // Conversely if we're in that scope, it's likely we'll reference them.
  if (Query == CodeComplete) {
    // The narrower the scope where a symbol is visible, the more likely it is
    // to be relevant when it is available.
    switch (Scope) {
    case GlobalScope:
      break;
    case FileScope:
      Score *= 1.5;
      break;
    case ClassScope:
      Score *= 2;
      break;
    case FunctionScope:
      Score *= 4;
      break;
    }
  }

  return Score;
}

raw_ostream &operator<<(raw_ostream &OS, const SymbolRelevanceSignals &S) {
  OS << formatv("=== Symbol relevance: {0}\n", S.evaluate());
  OS << formatv("\tName match: {0}\n", S.NameMatch);
  OS << formatv("\tForbidden: {0}\n", S.Forbidden);
  OS << formatv("\tSymbol URI: {0}\n", S.SymbolURI);
  if (S.FileProximityMatch) {
    auto Score = proximityScore(S.SymbolURI, S.FileProximityMatch);
    OS << formatv("\tIndex proximity: {0} (distance={1})\n", Score.first,
                  Score.second);
  }
  OS << formatv("\tSema proximity: {0}\n", S.SemaProximityScore);
  OS << formatv("\tQuery type: {0}\n", static_cast<int>(S.Query));
  OS << formatv("\tScope: {0}\n", static_cast<int>(S.Scope));
  return OS;
}

float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance) {
  return SymbolQuality * SymbolRelevance;
}

// Produces an integer that sorts in the same order as F.
// That is: a < b <==> encodeFloat(a) < encodeFloat(b).
static uint32_t encodeFloat(float F) {
  static_assert(std::numeric_limits<float>::is_iec559, "");
  constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1);

  // Get the bits of the float. Endianness is the same as for integers.
  uint32_t U = FloatToBits(F);
  // IEEE 754 floats compare like sign-magnitude integers.
  if (U & TopBit)    // Negative float.
    return 0 - U;    // Map onto the low half of integers, order reversed.
  return U + TopBit; // Positive floats map onto the high half of integers.
}

std::string sortText(float Score, llvm::StringRef Name) {
  // We convert -Score to an integer, and hex-encode for readability.
  // Example: [0.5, "foo"] -> "41000000foo"
  std::string S;
  llvm::raw_string_ostream OS(S);
  write_hex(OS, encodeFloat(-Score), llvm::HexPrintStyle::Lower,
            /*Width=*/2 * sizeof(Score));
  OS << Name;
  OS.flush();
  return S;
}

} // namespace clangd
} // namespace clang
<|endoftext|>


<commit_before>#ifndef BLOWMORPH_ENET_WRAPPER_ENET_HPP_
#define BLOWMORPH_ENET_WRAPPER_ENET_HPP_

#include "base/macros.hpp"
#include "base/pstdint.hpp"

#include "enet-wrapper/server_host.hpp"
#include "enet-wrapper/client_host.hpp"
#include "enet-wrapper/event.hpp"
#include "enet-wrapper/peer.hpp"

#include "library.hpp"

namespace bm {

// TODO: write comments.
class Enet {
public:
  // TODO: write comments.
  BM_ENET_DECL Enet();

  // TODO: write comments.
  BM_ENET_DECL ~Enet();

  // Call this to ensure that ENet has been successfully initialized.
  // XXX[2.8.2012 alex]: fixme written in cp1251
  // FIXME: ,      false.
  // FIXME:       ?
  BM_ENET_DECL bool IsInitialized() const;

  // Creates 'ServerHost' bound to 'port'.
  // You may specify 'channel_count' - number of channels to be used.
  // You may specify incoming and outgoing bandwidth of the server in bytes
  // per second. Specifying '0' for these two options will cause ENet to rely
  // entirely upon its dynamic throttling algorithm to manage bandwidth.
  // Returned 'ServerHost' should be deallocated manually using 'delete'.
  BM_ENET_DECL ServerHost* CreateServerHost(
    uint16_t port,
    size_t peer_count = 32,
    size_t channel_count = 1,
    uint32_t incoming_bandwith = 0,
    uint32_t outgoing_bandwith = 0
  );

  // Creates 'ClientHost'.
  // You may specify 'channel_count' - number of channels to be used.
  // You may specify incoming and outgoing bandwidth of the server in bytes
  // per second. Specifying '0' for these two options will cause ENet to rely
  // entirely upon its dynamic throttling algorithm to manage bandwidth.
  // Returned 'ClientHost' should be deallocated manually using 'delete'.
  BM_ENET_DECL ClientHost* CreateClientHost(
    size_t channel_count = 1,
    uint32_t incoming_bandwith = 0,
    uint32_t outgoing_bandwith = 0
  );

  // Creates non-initialized Event.
  // Returned 'Event' should be deallocated manually using 'delete'.
  BM_ENET_DECL Event* CreateEvent();

private:
  DISALLOW_COPY_AND_ASSIGN(Enet);

  enum {
    STATE_CREATED,
    STATE_INITIALIZED,
  } _state;
};

} // namespace bm

#endif // BLOWMORPH_ENET_WRAPPER_ENET_HPP_
<commit_msg>Converted enet.hpp to utf8<commit_after>#ifndef BLOWMORPH_ENET_WRAPPER_ENET_HPP_
#define BLOWMORPH_ENET_WRAPPER_ENET_HPP_

#include "base/macros.hpp"
#include "base/pstdint.hpp"

#include "enet-wrapper/server_host.hpp"
#include "enet-wrapper/client_host.hpp"
#include "enet-wrapper/event.hpp"
#include "enet-wrapper/peer.hpp"

#include "library.hpp"

namespace bm {

// TODO: write comments.
class Enet {
public:
  // TODO: write comments.
  BM_ENET_DECL Enet();

  // TODO: write comments.
  BM_ENET_DECL ~Enet();

  // Call this to ensure that ENet has been successfully initialized.
  // XXX[2.8.2012 alex]: fixme written in cp1251
  // FIXME: непонятно, при какой ситуации может вернуться false.
  // FIXME: почему бы не сделать этот класс синглтоном?
  BM_ENET_DECL bool IsInitialized() const;

  // Creates 'ServerHost' bound to 'port'.
  // You may specify 'channel_count' - number of channels to be used.
  // You may specify incoming and outgoing bandwidth of the server in bytes
  // per second. Specifying '0' for these two options will cause ENet to rely
  // entirely upon its dynamic throttling algorithm to manage bandwidth.
  // Returned 'ServerHost' should be deallocated manually using 'delete'.
  BM_ENET_DECL ServerHost* CreateServerHost(
    uint16_t port,
    size_t peer_count = 32,
    size_t channel_count = 1,
    uint32_t incoming_bandwith = 0,
    uint32_t outgoing_bandwith = 0
  );

  // Creates 'ClientHost'.
  // You may specify 'channel_count' - number of channels to be used.
  // You may specify incoming and outgoing bandwidth of the server in bytes
  // per second. Specifying '0' for these two options will cause ENet to rely
  // entirely upon its dynamic throttling algorithm to manage bandwidth.
  // Returned 'ClientHost' should be deallocated manually using 'delete'.
  BM_ENET_DECL ClientHost* CreateClientHost(
    size_t channel_count = 1,
    uint32_t incoming_bandwith = 0,
    uint32_t outgoing_bandwith = 0
  );

  // Creates non-initialized Event.
  // Returned 'Event' should be deallocated manually using 'delete'.
  BM_ENET_DECL Event* CreateEvent();

private:
  DISALLOW_COPY_AND_ASSIGN(Enet);

  enum {
    STATE_CREATED,
    STATE_INITIALIZED,
  } _state;
};

} // namespace bm

#endif // BLOWMORPH_ENET_WRAPPER_ENET_HPP_
<|endoftext|>


<commit_before>// Copyright 2015, Durachenko Aleksey V. <durachenko.aleksey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
#include "qsesppasyncsignalplot.h"
#include <QPainter>
#include "qseabstractsppasyncpeakdatasource.h"
#include "qseabstractsppsignalplotdelegate.h"
#include "qseabstractspppeakreply.h"
#include <QDebug>

QseSppAsyncSignalPlot::QseSppAsyncSignalPlot(QObject *parent) :
    QseAbstractSppSignalPlot(parent)
{
    m_dataSource = 0;
    m_reply = 0;
}

void QseSppAsyncSignalPlot::setDataSource(
        QseAbstractSppAsyncPeakDataSource *dataSource)
{
    if (m_dataSource == dataSource)
        return;

    if (m_dataSource)
        disconnect(m_dataSource, 0, this, 0);

    m_dataSource = dataSource;
    if (m_dataSource)
    {
        connect(m_dataSource, SIGNAL(dataChanged()),
                this, SLOT(dataSource_dataChanged()));
        connect(m_dataSource, SIGNAL(dataChanged(qint64,qint64)),
                this, SLOT(dataSource_dataChanged(qint64,qint64)));
        connect(m_dataSource, SIGNAL(destroyed()),
                this, SLOT(dataSource_destroyed()));
    }

    setUpdateOnce(true);
}

void QseSppAsyncSignalPlot::draw(QPainter *painter, const QRect &rect,
        const QseSppGeometry &geometry)
{
    if (isVisible(rect, geometry))
    {
        QseSppGeometry g = geometry;
        if (g.x() < m_dataSource->minIndex())
            g.setX(m_dataSource->minIndex());
        QseSppPeakRequest request(g, rect);
        if (/*hasChanges(rect, geometry) ||*/ m_lastRequst != request)
        {
            if (m_reply)
            {
                disconnect(m_reply, 0, this, 0);
                m_reply->abort();
                m_reply->deleteLater();
            }

            m_reply = m_dataSource->read(request);
            connect(m_reply, SIGNAL(finished(QsePeakArray,QseSppPeakRequest)),
                    this, SLOT(reply_finished(QsePeakArray,QseSppPeakRequest)),
                    Qt::QueuedConnection);
            connect(m_reply, SIGNAL(aborted(QseSppPeakRequest)),
                    this, SLOT(reply_aborted(QseSppPeakRequest)),
                    Qt::QueuedConnection);

            if (m_lastRequst.spp() != request.spp())
                m_peaks.clear();
        }

        drawAvaiblePeaks(painter, rect, geometry);
    }

    QseAbstractSppSignalPlot::draw(painter, rect, geometry);
}

void QseSppAsyncSignalPlot::dataSource_dataChanged()
{
    m_peaks.clear();
    setUpdateOnce(true);
}

void QseSppAsyncSignalPlot::dataSource_dataChanged(qint64 /*first*/,
        qint64 /*last*/)
{
    dataSource_dataChanged();
}

void QseSppAsyncSignalPlot::dataSource_destroyed()
{
    m_dataSource = 0;
}

void QseSppAsyncSignalPlot::reply_aborted(const QseSppPeakRequest &/*request*/)
{
    m_reply->deleteLater();
    m_reply = 0;
}

void QseSppAsyncSignalPlot::reply_finished(const QsePeakArray &peaks,
        const QseSppPeakRequest &request)
{
    m_peaks = peaks;
    m_lastRequst = request;
    m_peaksFirstIndex = m_lastRequst.x();
    m_reply->deleteLater();
    m_reply = 0;
    setUpdateOnce(true);
}

void QseSppAsyncSignalPlot::drawAvaiblePeaks(QPainter *painter,
        const QRect &rect, const QseSppGeometry &geometry)
{
    if (m_peaks.isEmpty())
        return;

    // first index of visible part of peaks
    qint64 firstIndex = 0;
    if (m_peaksFirstIndex < geometry.x())
        firstIndex = geometry.x() - m_peaksFirstIndex;
    if (geometry.samplesPerPixel() > 0)
        firstIndex /= geometry.samplesPerPixel();
    // all peaks are invisible
    if (firstIndex >= m_peaks.count())
        return;

    // free space in pixels between left bound and first peaks
    int space = 0;
    if (m_peaksFirstIndex > geometry.x())
        space = QseSppGeometry::widthFromSamples(
                    geometry, m_peaksFirstIndex - geometry.x());

    // this value will be added to the y coordiante of the each peaks
    const double dy = calcDy(rect);

    // draw the peaks
    if (m_peaks.hasMaximums())
        plotDelegate()->drawAsPeaks(painter, rect, geometry,
                m_peaks, firstIndex, space, 0, dy);
    else
        plotDelegate()->drawAsLines(painter, rect, geometry,
                m_peaks, firstIndex, space, 0, dy);
}

QseAbstractPeakDataSource *QseSppAsyncSignalPlot::usedDataSource() const
{
    return qobject_cast<QseAbstractPeakDataSource *>(m_dataSource);
}
<commit_msg>fix QCoreApplication::postEvent: Unexpected null receiver<commit_after>// Copyright 2015, Durachenko Aleksey V. <durachenko.aleksey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
#include "qsesppasyncsignalplot.h"
#include <QPainter>
#include "qseabstractsppasyncpeakdatasource.h"
#include "qseabstractsppsignalplotdelegate.h"
#include "qseabstractspppeakreply.h"
#include <QDebug>

QseSppAsyncSignalPlot::QseSppAsyncSignalPlot(QObject *parent) :
    QseAbstractSppSignalPlot(parent)
{
    m_dataSource = 0;
    m_reply = 0;
}

void QseSppAsyncSignalPlot::setDataSource(
        QseAbstractSppAsyncPeakDataSource *dataSource)
{
    if (m_dataSource == dataSource)
        return;

    if (m_dataSource)
        disconnect(m_dataSource, 0, this, 0);

    m_dataSource = dataSource;
    if (m_dataSource)
    {
        connect(m_dataSource, SIGNAL(dataChanged()),
                this, SLOT(dataSource_dataChanged()));
        connect(m_dataSource, SIGNAL(dataChanged(qint64,qint64)),
                this, SLOT(dataSource_dataChanged(qint64,qint64)));
        connect(m_dataSource, SIGNAL(destroyed()),
                this, SLOT(dataSource_destroyed()));
    }

    setUpdateOnce(true);
}

void QseSppAsyncSignalPlot::draw(QPainter *painter, const QRect &rect,
        const QseSppGeometry &geometry)
{
    if (isVisible(rect, geometry))
    {
        QseSppGeometry g = geometry;
        if (g.x() < m_dataSource->minIndex())
            g.setX(m_dataSource->minIndex());
        QseSppPeakRequest request(g, rect);
        if (/*hasChanges(rect, geometry) ||*/ m_lastRequst != request)
        {
            if (m_reply)
            {
                disconnect(m_reply, 0, this, 0);
                m_reply->abort();
                QMetaObject::invokeMethod(m_reply, "deleteLater", Qt::QueuedConnection);
                //m_reply->deleteLater();
            }

            m_reply = m_dataSource->read(request);
            connect(m_reply, SIGNAL(finished(QsePeakArray,QseSppPeakRequest)),
                    this, SLOT(reply_finished(QsePeakArray,QseSppPeakRequest)),
                    Qt::QueuedConnection);
            connect(m_reply, SIGNAL(aborted(QseSppPeakRequest)),
                    this, SLOT(reply_aborted(QseSppPeakRequest)),
                    Qt::QueuedConnection);

            if (m_lastRequst.spp() != request.spp())
                m_peaks.clear();
        }

        drawAvaiblePeaks(painter, rect, geometry);
    }

    QseAbstractSppSignalPlot::draw(painter, rect, geometry);
}

void QseSppAsyncSignalPlot::dataSource_dataChanged()
{
    m_peaks.clear();
    setUpdateOnce(true);
}

void QseSppAsyncSignalPlot::dataSource_dataChanged(qint64 /*first*/,
        qint64 /*last*/)
{
    dataSource_dataChanged();
}

void QseSppAsyncSignalPlot::dataSource_destroyed()
{
    m_dataSource = 0;
}

void QseSppAsyncSignalPlot::reply_aborted(const QseSppPeakRequest &/*request*/)
{
//    qDebug() << "abort";
    //m_reply->deleteLater();
    QMetaObject::invokeMethod(m_reply, "deleteLater", Qt::QueuedConnection);
    m_reply = 0;
}

void QseSppAsyncSignalPlot::reply_finished(const QsePeakArray &peaks,
        const QseSppPeakRequest &request)
{
//    qDebug() << "finished";
    m_peaks = peaks;
    m_lastRequst = request;
    m_peaksFirstIndex = m_lastRequst.x();
    //m_reply->deleteLater();
    QMetaObject::invokeMethod(m_reply, "deleteLater", Qt::QueuedConnection);
    m_reply = 0;
    setUpdateOnce(true);
}

void QseSppAsyncSignalPlot::drawAvaiblePeaks(QPainter *painter,
        const QRect &rect, const QseSppGeometry &geometry)
{
    if (m_peaks.isEmpty())
        return;

    // first index of visible part of peaks
    qint64 firstIndex = 0;
    if (m_peaksFirstIndex < geometry.x())
        firstIndex = geometry.x() - m_peaksFirstIndex;
    if (geometry.samplesPerPixel() > 0)
        firstIndex /= geometry.samplesPerPixel();
    // all peaks are invisible
    if (firstIndex >= m_peaks.count())
        return;

    // free space in pixels between left bound and first peaks
    int space = 0;
    if (m_peaksFirstIndex > geometry.x())
        space = QseSppGeometry::widthFromSamples(
                    geometry, m_peaksFirstIndex - geometry.x());

    // this value will be added to the y coordiante of the each peaks
    const double dy = calcDy(rect);

    // draw the peaks
    if (m_peaks.hasMaximums())
        plotDelegate()->drawAsPeaks(painter, rect, geometry,
                m_peaks, firstIndex, space, 0, dy);
    else
        plotDelegate()->drawAsLines(painter, rect, geometry,
                m_peaks, firstIndex, space, 0, dy);
}

QseAbstractPeakDataSource *QseSppAsyncSignalPlot::usedDataSource() const
{
    return qobject_cast<QseAbstractPeakDataSource *>(m_dataSource);
}
<|endoftext|>


<commit_before>/*!
 *  Copyright (c) 2018 by Contributors
 * \file graph_runtime_debug.cc
 */
#include <tvm/runtime/packed_func.h>
#include <tvm/runtime/registry.h>
#include <tvm/runtime/ndarray.h>
#include <chrono>
#include "../graph_runtime.h"

namespace tvm {
namespace runtime {

/*!
 * \brief Graph runtime with debug .
 *
 *  This is the extension of GraphRuntime class used for debugging
 *  TVM runtime PackedFunc API.
 */
class GraphRuntimeDebug : public GraphRuntime {
 public:
    /*!
     * \brief Run each operation and get the output.
     * \param index The index of op which needs to be run.
     */
  double DebugRun(size_t index) {
    CHECK(index < op_execs().size());
    TVMContext ctx = data_entry()[GetEntryId(index, 0)].operator->()->ctx;
    auto tbegin = std::chrono::high_resolution_clock::now();
    if (op_execs()[index]) {
      op_execs()[index]();
    }
    TVMSynchronize(ctx.device_type, ctx.device_id, nullptr);
    auto tend = std::chrono::high_resolution_clock::now();
    double time = std::chrono::duration_cast<std::chrono::duration<double> >(
        tend - tbegin).count();
    return time;
  }

  /*!
   * \brief Run each operation and get the output.
   * \param index The index of op which needs to be returned.
   * \param eid The Entry id of the op.
   */
  NDArray GetOutputByLayer(int index, int eid) {
    return data_entry()[GetEntryId(index, eid)];
  }

  /*!
   * \brief GetFunction Get the function based on input.
   * \param name The function which needs to be invoked.
   * \param sptr_to_self Packed function pointer.
   */
  PackedFunc GetFunction(const std::string& name,
                         const std::shared_ptr<ModuleNode>& sptr_to_self);

  /*!
   * \brief Get the node index given the name of node.
   * \param name The name of the node.
   * \return The index of node.
   */
  int GetNodeIndex(const std::string& name) const {
    for (size_t nid = 0; nid < GetNumOfNodes(); ++nid) {
      if (GetNodeName(nid) == name) {
        return static_cast<int>(nid);
      }
    }
    LOG(FATAL) << "cannot find " << name << " among nodex";
    return -1;
}

/*!
 * \brief Copy index-th node to data_out.
 *
 * This method will do a partial run of the the graph
 * from begining upto the index-th node and return output of index-th node.
 * This is costly operation and suggest to use only for debug porpose.
 *
 * \param index: The  index of the node.
 * \param data_out the node data.
 */
void DebugGetNodeOutput(int index, DLTensor* data_out) {
  CHECK_LT(static_cast<size_t>(index), op_execs().size());
  uint32_t eid = index;

  for (size_t i = 0; i < op_execs().size(); ++i) {
    if (op_execs()[i]) op_execs()[i]();
    if (static_cast<int>(i) == index) break;
  }

  data_entry()[eid].CopyTo(data_out);
}
};

/*!
 * \brief GetFunction Get the function based on input.
 * \param name The function which needs to be invoked.
 * \param sptr_to_self Packed function pointer.
 */
PackedFunc GraphRuntimeDebug::GetFunction(
    const std::string& name,
    const std::shared_ptr<ModuleNode>& sptr_to_self) {
  // return member functions during query.
  if (name == "debug_run") {
    return PackedFunc([sptr_to_self, this](TVMArgs args, TVMRetValue* rv) {
        *rv = this->DebugRun(args[0]);
      });
  } else if (name == "get_output_by_layer") {
    return PackedFunc([sptr_to_self, this](TVMArgs args, TVMRetValue* rv) {
        *rv = this->GetOutputByLayer(args[0], args[1]);
      });
  } else if (name == "debug_get_output") {
    return PackedFunc([sptr_to_self, this](TVMArgs args, TVMRetValue* rv) {
        if (args[0].type_code() == kStr) {
          this->DebugGetNodeOutput(this->GetNodeIndex(args[0]), args[1]);
        } else {
          this->DebugGetNodeOutput(args[0], args[1]);
        }
      });
  } else {
    return GraphRuntime::GetFunction(name, sptr_to_self);
  }
}

/*!
 * \brief GraphRuntimeDebugCreate Get the function based on input.
 * \param sym_json The graph symbol in json format.
 * \param m Compiled module which will be loaded.
 * \param ctxs All devices contexts.
 */
  Module GraphRuntimeDebugCreate(const std::string& sym_json,
                                 const tvm::runtime::Module& m,
                                 const std::vector<TVMContext>& ctxs) {
  std::shared_ptr<GraphRuntimeDebug> exec = std::make_shared<GraphRuntimeDebug>();
  exec->Init(sym_json, m, ctxs);
  return Module(exec);
}

TVM_REGISTER_GLOBAL("tvm.graph_runtime_debug.create")
.set_body([](TVMArgs args, TVMRetValue* rv) {
    CHECK_GE(args.num_args, 4)
        << "The expected number of arguments for graph_runtime.create is "
           "at least 4, but it has "
        << args.num_args;
    *rv = GraphRuntimeDebugCreate(args[0], args[1], GetAllContext(args));
  });
}  // namespace runtime
}  // namespace tvm
<commit_msg>[RUNTIME] Fix debug runtime i386 build (#1818)<commit_after>/*!
 *  Copyright (c) 2018 by Contributors
 * \file graph_runtime_debug.cc
 */
#include <tvm/runtime/packed_func.h>
#include <tvm/runtime/registry.h>
#include <tvm/runtime/ndarray.h>
#include <chrono>
#include "../graph_runtime.h"

namespace tvm {
namespace runtime {

/*!
 * \brief Graph runtime with debug .
 *
 *  This is the extension of GraphRuntime class used for debugging
 *  TVM runtime PackedFunc API.
 */
class GraphRuntimeDebug : public GraphRuntime {
 public:
  /*!
   * \brief Run each operation and get the output.
   * \param index The index of op which needs to be run.
   * \return the elapsed time.
   */
  double DebugRun(size_t index) {
    CHECK(index < op_execs().size());
    TVMContext ctx = data_entry()[GetEntryId(index, 0)].operator->()->ctx;
    auto tbegin = std::chrono::high_resolution_clock::now();
    if (op_execs()[index]) {
      op_execs()[index]();
    }
    TVMSynchronize(ctx.device_type, ctx.device_id, nullptr);
    auto tend = std::chrono::high_resolution_clock::now();
    double time = std::chrono::duration_cast<std::chrono::duration<double> >(
        tend - tbegin).count();
    return time;
  }

  /*!
   * \brief Run each operation and get the output.
   * \param index The index of op which needs to be returned.
   * \param eid The Entry id of the op.
   */
  NDArray GetOutputByLayer(int index, int eid) {
    return data_entry()[GetEntryId(index, eid)];
  }

  /*!
   * \brief GetFunction Get the function based on input.
   * \param name The function which needs to be invoked.
   * \param sptr_to_self Packed function pointer.
   */
  PackedFunc GetFunction(const std::string& name,
                         const std::shared_ptr<ModuleNode>& sptr_to_self);

  /*!
   * \brief Get the node index given the name of node.
   * \param name The name of the node.
   * \return The index of node.
   */
  int GetNodeIndex(const std::string& name) const {
    for (size_t nid = 0; nid < GetNumOfNodes(); ++nid) {
      if (GetNodeName(nid) == name) {
        return static_cast<int>(nid);
      }
    }
    LOG(FATAL) << "cannot find " << name << " among nodex";
    return -1;
}

/*!
 * \brief Copy index-th node to data_out.
 *
 * This method will do a partial run of the the graph
 * from begining upto the index-th node and return output of index-th node.
 * This is costly operation and suggest to use only for debug porpose.
 *
 * \param index: The  index of the node.
 * \param data_out the node data.
 */
void DebugGetNodeOutput(int index, DLTensor* data_out) {
  CHECK_LT(static_cast<size_t>(index), op_execs().size());
  uint32_t eid = index;

  for (size_t i = 0; i < op_execs().size(); ++i) {
    if (op_execs()[i]) op_execs()[i]();
    if (static_cast<int>(i) == index) break;
  }

  data_entry()[eid].CopyTo(data_out);
}
};

/*!
 * \brief GetFunction Get the function based on input.
 * \param name The function which needs to be invoked.
 * \param sptr_to_self Packed function pointer.
 */
PackedFunc GraphRuntimeDebug::GetFunction(
    const std::string& name,
    const std::shared_ptr<ModuleNode>& sptr_to_self) {
  // return member functions during query.
  if (name == "debug_run") {
    return PackedFunc([sptr_to_self, this](TVMArgs args, TVMRetValue* rv) {
        *rv = this->DebugRun(static_cast<size_t>(args[0].operator int64_t()));
      });
  } else if (name == "get_output_by_layer") {
    return PackedFunc([sptr_to_self, this](TVMArgs args, TVMRetValue* rv) {
        *rv = this->GetOutputByLayer(args[0], args[1]);
      });
  } else if (name == "debug_get_output") {
    return PackedFunc([sptr_to_self, this](TVMArgs args, TVMRetValue* rv) {
        if (args[0].type_code() == kStr) {
          this->DebugGetNodeOutput(this->GetNodeIndex(args[0]), args[1]);
        } else {
          this->DebugGetNodeOutput(args[0], args[1]);
        }
      });
  } else {
    return GraphRuntime::GetFunction(name, sptr_to_self);
  }
}

/*!
 * \brief GraphRuntimeDebugCreate Get the function based on input.
 * \param sym_json The graph symbol in json format.
 * \param m Compiled module which will be loaded.
 * \param ctxs All devices contexts.
 */
Module GraphRuntimeDebugCreate(const std::string& sym_json,
                               const tvm::runtime::Module& m,
                               const std::vector<TVMContext>& ctxs) {
  std::shared_ptr<GraphRuntimeDebug> exec = std::make_shared<GraphRuntimeDebug>();
  exec->Init(sym_json, m, ctxs);
  return Module(exec);
}

TVM_REGISTER_GLOBAL("tvm.graph_runtime_debug.create")
.set_body([](TVMArgs args, TVMRetValue* rv) {
    CHECK_GE(args.num_args, 4)
        << "The expected number of arguments for graph_runtime.create is "
           "at least 4, but it has "
        << args.num_args;
    *rv = GraphRuntimeDebugCreate(args[0], args[1], GetAllContext(args));
  });
}  // namespace runtime
}  // namespace tvm
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 *
 * Authors: Nathan Binkert
 *          Steve Reinhardt
 *          Ali Saidi
 */

#ifndef __ARCH_ARM_PAGETABLE_H__
#define __ARCH_ARM_PAGETABLE_H__

#include "arch/arm/isa_traits.hh"
#include "arch/arm/utility.hh"
#include "arch/arm/vtophys.hh"
#include "config/full_system.hh"

namespace ArmISA {

struct VAddr
{
    VAddr(Addr a) { panic("not implemented yet."); }
};

// ITB/DTB page table entry
struct PTE
{
    void serialize(std::ostream &os)
    {
        panic("Need to implement PTE serialization\n");
    }

    void unserialize(Checkpoint *cp, const std::string &section)
    {
        panic("Need to implement PTE serialization\n");
    }

};

// ITB/DTB table entry
struct TlbEntry
{
    Addr tag;               // virtual page number tag
    Addr ppn;               // physical page number
    uint8_t asn;            // address space number
    bool valid;             // valid page table entry

    //Construct an entry that maps to physical address addr.
    TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr)
    {
        tag = _vaddr >> PageShift;
        ppn = _paddr >> PageShift;
        asn = _asn;
        valid = true;
    }

    TlbEntry()
    {}

    void
    updateVaddr(Addr new_vaddr)
    {
        tag = new_vaddr >> PageShift;
    }

    Addr
    pageStart()
    {
        return ppn << PageShift;
    }

    void serialize(std::ostream &os);
    void unserialize(Checkpoint *cp, const std::string &section);
};

};
#endif // __ARCH_ARM_PAGETABLE_H__

<commit_msg>ARM: SE needs a definition for PageTable::serialize/unserialize<commit_after>/*
 * Copyright (c) 2010 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 *
 * Authors: Nathan Binkert
 *          Steve Reinhardt
 *          Ali Saidi
 */

#ifndef __ARCH_ARM_PAGETABLE_H__
#define __ARCH_ARM_PAGETABLE_H__

#include "arch/arm/isa_traits.hh"
#include "arch/arm/utility.hh"
#include "arch/arm/vtophys.hh"
#include "config/full_system.hh"

namespace ArmISA {

struct VAddr
{
    VAddr(Addr a) { panic("not implemented yet."); }
};

// ITB/DTB page table entry
struct PTE
{
    void serialize(std::ostream &os)
    {
        panic("Need to implement PTE serialization\n");
    }

    void unserialize(Checkpoint *cp, const std::string &section)
    {
        panic("Need to implement PTE serialization\n");
    }

};

// ITB/DTB table entry
struct TlbEntry
{
    Addr tag;               // virtual page number tag
    Addr ppn;               // physical page number
    uint8_t asn;            // address space number
    bool valid;             // valid page table entry

    //Construct an entry that maps to physical address addr.
    TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr)
    {
        tag = _vaddr >> PageShift;
        ppn = _paddr >> PageShift;
        asn = _asn;
        valid = true;
    }

    TlbEntry()
    {}

    void
    updateVaddr(Addr new_vaddr)
    {
        tag = new_vaddr >> PageShift;
    }

    Addr
    pageStart()
    {
        return ppn << PageShift;
    }

    void serialize(std::ostream &os) { panic("Need to Implement\n"); }
    void unserialize(Checkpoint *cp, const std::string &section)
                   { panic("Need to Implement\n");}
};

};
#endif // __ARCH_ARM_PAGETABLE_H__

<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include <algorithm>

#include <gtest/gtest.h>

#include "../../cvmfs/platform.h"
#include "../../cvmfs/util.h"
#include "../../cvmfs/xattr.h"

using namespace std;  // NOLINT

class T_Xattr : public ::testing::Test {
 protected:
  virtual void SetUp() {
    default_list.Set("keya", "valuea");
    default_list.Set("keyb", "valueb");
    default_list.Set("empty_key", "");
  }

  unsigned int CountAttributesInFile(const std::string &path) const {
    ssize_t sz_list = platform_llistxattr(path.c_str(), NULL, 0);
    if (sz_list <= 0) {
      return 0;
    }

    char *list = reinterpret_cast<char *>(malloc(sz_list));
    sz_list = platform_llistxattr(path.c_str(), list, sz_list);
    if (sz_list <= 0) {
      return 0;
    }

    const std::string attrs(list, sz_list);
    free(list);
    return std::count(attrs.begin(), attrs.end(), '\0');
  }

  XattrList default_list;
};

TEST_F(T_Xattr, CreateFromFile) {
  EXPECT_EQ(NULL, XattrList::CreateFromFile("/no/such/file"));

  // Create extended attributes
  string tmp_path;
  FILE *f = CreateTempFile("/tmp/cvmfs-test", 0600, "w", &tmp_path);
  ASSERT_TRUE(f != NULL);
  fclose(f);
  UnlinkGuard unlink_guard(tmp_path);

  UniquePtr<XattrList> from_file1(XattrList::CreateFromFile(tmp_path));
  ASSERT_TRUE(from_file1.IsValid());
  ASSERT_TRUE(from_file1->IsEmpty());

  string value;
  ASSERT_TRUE(platform_setxattr(tmp_path, "user.test", "value"));
  UniquePtr<XattrList> from_file2(XattrList::CreateFromFile(tmp_path));
  ASSERT_TRUE(from_file2.IsValid());
  EXPECT_EQ(1U, from_file2->ListKeys().size());
  EXPECT_TRUE(from_file2->Get("user.test", &value));
  EXPECT_EQ("value", value);

#ifndef __APPLE__
  ASSERT_TRUE(platform_setxattr(tmp_path, "user.test2", "value2"));
  string long_string = "user." + string(250, 'x');
  string too_long_string = "user." + string(300, 'x');
  ASSERT_TRUE(platform_setxattr(tmp_path, long_string, long_string));
  ASSERT_TRUE(platform_setxattr(tmp_path, "user.test3", too_long_string));
  UniquePtr<XattrList> from_file3(XattrList::CreateFromFile(tmp_path));
  ASSERT_TRUE(from_file3.IsValid());
  EXPECT_EQ(3U, from_file3->ListKeys().size());
  EXPECT_TRUE(from_file3->Get("user.test", &value));
  EXPECT_EQ("value", value);
  EXPECT_TRUE(from_file3->Get("user.test2", &value));
  EXPECT_EQ("value2", value);
  EXPECT_TRUE(from_file3->Get(long_string, &value));
  EXPECT_EQ(long_string, value);
#endif
}

TEST_F(T_Xattr, Deserialize) {
  unsigned char *buf;
  unsigned size;
  default_list.Serialize(&buf, &size);
  EXPECT_GT(size, 0U);
  EXPECT_TRUE(buf != NULL);

  UniquePtr<XattrList> xattr_list(XattrList::Deserialize(buf, size));
  free(buf);
  ASSERT_TRUE(xattr_list.IsValid());
  EXPECT_EQ(3U, xattr_list->ListKeys().size());
  string value;
  EXPECT_TRUE(xattr_list->Get("keya", &value));
  EXPECT_EQ("valuea", value);
  EXPECT_TRUE(xattr_list->Get("keyb", &value));
  EXPECT_EQ("valueb", value);
  EXPECT_TRUE(xattr_list->Get("empty_key", &value));
  EXPECT_EQ("", value);
}

TEST_F(T_Xattr, DeserializeNull) {
  UniquePtr<XattrList> xattr_list(XattrList::Deserialize(NULL, 0));
  ASSERT_TRUE(xattr_list.IsValid());
  EXPECT_EQ(0U, xattr_list->ListKeys().size());
}

TEST_F(T_Xattr, DeserializeInvalid) {
  unsigned char *buf;
  unsigned size;
  default_list.Serialize(&buf, &size);
  EXPECT_GT(size, 0U);
  EXPECT_TRUE(buf != NULL);

  UniquePtr<XattrList> xl1(XattrList::Deserialize(buf, 0));
  EXPECT_FALSE(xl1.IsValid());

  buf[0] = 255;
  UniquePtr<XattrList> xl2(XattrList::Deserialize(buf, size));
  EXPECT_FALSE(xl2.IsValid());
  buf[0] = XattrList::kVersion;

  UniquePtr<XattrList> xl3(XattrList::Deserialize(buf, 3));
  EXPECT_FALSE(xl3.IsValid());

  UniquePtr<XattrList> xl4(XattrList::Deserialize(buf, 5));
  EXPECT_FALSE(xl4.IsValid());

  unsigned char save0, save1;
  save0 = buf[2];
  save1 = buf[3];
  buf[2] = 0;
  buf[3] = 0;
  UniquePtr<XattrList> xl5(XattrList::Deserialize(buf, size));
  EXPECT_FALSE(xl5.IsValid());
  buf[3] = save1;
  UniquePtr<XattrList> xl6(XattrList::Deserialize(buf, size));
  EXPECT_FALSE(xl6.IsValid());

  buf[2] = save0;
  UniquePtr<XattrList> xl7(XattrList::Deserialize(buf, size));
  EXPECT_TRUE(xl7.IsValid());

  free(buf);
}

TEST_F(T_Xattr, Get) {
  string value;
  EXPECT_TRUE(default_list.Get("keya", &value));
  EXPECT_EQ("valuea", value);
  EXPECT_TRUE(default_list.Get("empty_key", &value));
  EXPECT_EQ("", value);
  EXPECT_FALSE(default_list.Get("not here", &value));
}

TEST_F(T_Xattr, ListKeys) {
  XattrList empty;
  EXPECT_TRUE(empty.ListKeys().empty());
  ASSERT_EQ(3U, default_list.ListKeys().size());
  EXPECT_EQ("empty_key", default_list.ListKeys()[0]);
  EXPECT_EQ("keya", default_list.ListKeys()[1]);
  EXPECT_EQ("keyb", default_list.ListKeys()[2]);
}

TEST_F(T_Xattr, ListKeysPosix) {
  const char base_list[] = "user.a\0user.b\0keya\0";
  string existing_list(base_list, sizeof(base_list)-1);
  XattrList empty;
  EXPECT_EQ("", empty.ListKeysPosix(""));
  const char expect1[] = "user.a\0user.b\0keya\0";
  EXPECT_EQ(string(expect1, sizeof(expect1)-1),
            empty.ListKeysPosix(existing_list));
  const char expect2[] = "empty_key\0keya\0keyb\0";
  EXPECT_EQ(string(expect2, sizeof(expect2)-1),
            default_list.ListKeysPosix(""));
  const char expect3[] = "user.a\0user.b\0empty_key\0keya\0keyb\0";
  EXPECT_EQ(string(expect3, sizeof(expect3)-1),
            default_list.ListKeysPosix(existing_list));
}

TEST_F(T_Xattr, Set) {
  string value;
  // Set a key
  EXPECT_TRUE(default_list.Set("keyc", "valuec"));
  EXPECT_TRUE(default_list.Get("keyc", &value));
  EXPECT_EQ("valuec", value);
  // Change a key
  EXPECT_TRUE(default_list.Set("keyc", ""));
  EXPECT_TRUE(default_list.Get("keyc", &value));
  EXPECT_EQ("", value);

  // Invalid operations
  string longstring(257, 'a');
  EXPECT_FALSE(default_list.Set(longstring, "value"));
  EXPECT_FALSE(default_list.Set("key", longstring));
  string nullstring(1, '\0');
  EXPECT_FALSE(default_list.Set(nullstring, "value"));

  XattrList new_list;
  for (unsigned i = 0; i < 256; ++i) {
    EXPECT_TRUE(new_list.Set(StringifyInt(i), ""));
  }
  EXPECT_FALSE(new_list.Set("256", ""));
}

TEST_F(T_Xattr, Remove) {
  string value;
  EXPECT_TRUE(default_list.Get("keya", &value));
  EXPECT_TRUE(default_list.Remove("keya"));
  EXPECT_FALSE(default_list.Get("keya", &value));
  EXPECT_FALSE(default_list.Remove("keya"));
}

TEST_F(T_Xattr, IsEmpty) {
  EXPECT_TRUE(XattrList().IsEmpty());
  EXPECT_FALSE(default_list.IsEmpty());
  vector<string> keys = default_list.ListKeys();
  for (unsigned i = 0; i < keys.size(); ++i) {
    EXPECT_TRUE(default_list.Remove(keys[i]));
  }
  EXPECT_TRUE(default_list.IsEmpty());
}

// The normal serialization part is tested as part of Deserialize
TEST_F(T_Xattr, SerializeNull) {
  unsigned char *buf;
  unsigned size;
  XattrList empty_list;
  empty_list.Serialize(&buf, &size);
  EXPECT_EQ(NULL, buf);
  EXPECT_EQ(0U, size);
}

TEST_F(T_Xattr, Limits) {
  XattrList large_list;
  string large_value(256, 'a');
  for (unsigned i = 0; i < 256; ++i) {
    char hex[3];
    snprintf(hex, sizeof(hex), "%02x", i);
    string large_key(128, hex[0]);
    large_key += string(128, hex[1]);
    EXPECT_TRUE(large_list.Set(large_key, large_value));
  }
  EXPECT_EQ(256U, large_list.ListKeys().size());
  for (unsigned i = 0; i < 256; ++i) {
    string value;
    char hex[3];
    snprintf(hex, sizeof(hex), "%02x", i);
    string large_key(128, hex[0]);
    large_key += string(128, hex[1]);
    EXPECT_TRUE(large_list.Get(large_key, &value));
    EXPECT_EQ(large_value, value);
  }
}
<commit_msg>Cosmetics: using naming scheme for tmp file<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include <algorithm>

#include <gtest/gtest.h>

#include "../../cvmfs/platform.h"
#include "../../cvmfs/util.h"
#include "../../cvmfs/xattr.h"

using namespace std;  // NOLINT

class T_Xattr : public ::testing::Test {
 protected:
  virtual void SetUp() {
    default_list.Set("keya", "valuea");
    default_list.Set("keyb", "valueb");
    default_list.Set("empty_key", "");
  }

  unsigned int CountAttributesInFile(const std::string &path) const {
    ssize_t sz_list = platform_llistxattr(path.c_str(), NULL, 0);
    if (sz_list <= 0) {
      return 0;
    }

    char *list = reinterpret_cast<char *>(malloc(sz_list));
    sz_list = platform_llistxattr(path.c_str(), list, sz_list);
    if (sz_list <= 0) {
      return 0;
    }

    const std::string attrs(list, sz_list);
    free(list);
    return std::count(attrs.begin(), attrs.end(), '\0');
  }

  XattrList default_list;
};

TEST_F(T_Xattr, CreateFromFile) {
  EXPECT_EQ(NULL, XattrList::CreateFromFile("/no/such/file"));

  // Create extended attributes
  string tmp_path;
  FILE *f = CreateTempFile("/tmp/cvmfs_ut_xattr", 0600, "w", &tmp_path);
  ASSERT_TRUE(f != NULL);
  fclose(f);
  UnlinkGuard unlink_guard(tmp_path);

  UniquePtr<XattrList> from_file1(XattrList::CreateFromFile(tmp_path));
  ASSERT_TRUE(from_file1.IsValid());
  ASSERT_TRUE(from_file1->IsEmpty());

  string value;
  ASSERT_TRUE(platform_setxattr(tmp_path, "user.test", "value"));
  UniquePtr<XattrList> from_file2(XattrList::CreateFromFile(tmp_path));
  ASSERT_TRUE(from_file2.IsValid());
  EXPECT_EQ(1U, from_file2->ListKeys().size());
  EXPECT_TRUE(from_file2->Get("user.test", &value));
  EXPECT_EQ("value", value);

#ifndef __APPLE__
  ASSERT_TRUE(platform_setxattr(tmp_path, "user.test2", "value2"));
  string long_string = "user." + string(250, 'x');
  string too_long_string = "user." + string(300, 'x');
  ASSERT_TRUE(platform_setxattr(tmp_path, long_string, long_string));
  ASSERT_TRUE(platform_setxattr(tmp_path, "user.test3", too_long_string));
  UniquePtr<XattrList> from_file3(XattrList::CreateFromFile(tmp_path));
  ASSERT_TRUE(from_file3.IsValid());
  EXPECT_EQ(3U, from_file3->ListKeys().size());
  EXPECT_TRUE(from_file3->Get("user.test", &value));
  EXPECT_EQ("value", value);
  EXPECT_TRUE(from_file3->Get("user.test2", &value));
  EXPECT_EQ("value2", value);
  EXPECT_TRUE(from_file3->Get(long_string, &value));
  EXPECT_EQ(long_string, value);
#endif
}

TEST_F(T_Xattr, Deserialize) {
  unsigned char *buf;
  unsigned size;
  default_list.Serialize(&buf, &size);
  EXPECT_GT(size, 0U);
  EXPECT_TRUE(buf != NULL);

  UniquePtr<XattrList> xattr_list(XattrList::Deserialize(buf, size));
  free(buf);
  ASSERT_TRUE(xattr_list.IsValid());
  EXPECT_EQ(3U, xattr_list->ListKeys().size());
  string value;
  EXPECT_TRUE(xattr_list->Get("keya", &value));
  EXPECT_EQ("valuea", value);
  EXPECT_TRUE(xattr_list->Get("keyb", &value));
  EXPECT_EQ("valueb", value);
  EXPECT_TRUE(xattr_list->Get("empty_key", &value));
  EXPECT_EQ("", value);
}

TEST_F(T_Xattr, DeserializeNull) {
  UniquePtr<XattrList> xattr_list(XattrList::Deserialize(NULL, 0));
  ASSERT_TRUE(xattr_list.IsValid());
  EXPECT_EQ(0U, xattr_list->ListKeys().size());
}

TEST_F(T_Xattr, DeserializeInvalid) {
  unsigned char *buf;
  unsigned size;
  default_list.Serialize(&buf, &size);
  EXPECT_GT(size, 0U);
  EXPECT_TRUE(buf != NULL);

  UniquePtr<XattrList> xl1(XattrList::Deserialize(buf, 0));
  EXPECT_FALSE(xl1.IsValid());

  buf[0] = 255;
  UniquePtr<XattrList> xl2(XattrList::Deserialize(buf, size));
  EXPECT_FALSE(xl2.IsValid());
  buf[0] = XattrList::kVersion;

  UniquePtr<XattrList> xl3(XattrList::Deserialize(buf, 3));
  EXPECT_FALSE(xl3.IsValid());

  UniquePtr<XattrList> xl4(XattrList::Deserialize(buf, 5));
  EXPECT_FALSE(xl4.IsValid());

  unsigned char save0, save1;
  save0 = buf[2];
  save1 = buf[3];
  buf[2] = 0;
  buf[3] = 0;
  UniquePtr<XattrList> xl5(XattrList::Deserialize(buf, size));
  EXPECT_FALSE(xl5.IsValid());
  buf[3] = save1;
  UniquePtr<XattrList> xl6(XattrList::Deserialize(buf, size));
  EXPECT_FALSE(xl6.IsValid());

  buf[2] = save0;
  UniquePtr<XattrList> xl7(XattrList::Deserialize(buf, size));
  EXPECT_TRUE(xl7.IsValid());

  free(buf);
}

TEST_F(T_Xattr, Get) {
  string value;
  EXPECT_TRUE(default_list.Get("keya", &value));
  EXPECT_EQ("valuea", value);
  EXPECT_TRUE(default_list.Get("empty_key", &value));
  EXPECT_EQ("", value);
  EXPECT_FALSE(default_list.Get("not here", &value));
}

TEST_F(T_Xattr, ListKeys) {
  XattrList empty;
  EXPECT_TRUE(empty.ListKeys().empty());
  ASSERT_EQ(3U, default_list.ListKeys().size());
  EXPECT_EQ("empty_key", default_list.ListKeys()[0]);
  EXPECT_EQ("keya", default_list.ListKeys()[1]);
  EXPECT_EQ("keyb", default_list.ListKeys()[2]);
}

TEST_F(T_Xattr, ListKeysPosix) {
  const char base_list[] = "user.a\0user.b\0keya\0";
  string existing_list(base_list, sizeof(base_list)-1);
  XattrList empty;
  EXPECT_EQ("", empty.ListKeysPosix(""));
  const char expect1[] = "user.a\0user.b\0keya\0";
  EXPECT_EQ(string(expect1, sizeof(expect1)-1),
            empty.ListKeysPosix(existing_list));
  const char expect2[] = "empty_key\0keya\0keyb\0";
  EXPECT_EQ(string(expect2, sizeof(expect2)-1),
            default_list.ListKeysPosix(""));
  const char expect3[] = "user.a\0user.b\0empty_key\0keya\0keyb\0";
  EXPECT_EQ(string(expect3, sizeof(expect3)-1),
            default_list.ListKeysPosix(existing_list));
}

TEST_F(T_Xattr, Set) {
  string value;
  // Set a key
  EXPECT_TRUE(default_list.Set("keyc", "valuec"));
  EXPECT_TRUE(default_list.Get("keyc", &value));
  EXPECT_EQ("valuec", value);
  // Change a key
  EXPECT_TRUE(default_list.Set("keyc", ""));
  EXPECT_TRUE(default_list.Get("keyc", &value));
  EXPECT_EQ("", value);

  // Invalid operations
  string longstring(257, 'a');
  EXPECT_FALSE(default_list.Set(longstring, "value"));
  EXPECT_FALSE(default_list.Set("key", longstring));
  string nullstring(1, '\0');
  EXPECT_FALSE(default_list.Set(nullstring, "value"));

  XattrList new_list;
  for (unsigned i = 0; i < 256; ++i) {
    EXPECT_TRUE(new_list.Set(StringifyInt(i), ""));
  }
  EXPECT_FALSE(new_list.Set("256", ""));
}

TEST_F(T_Xattr, Remove) {
  string value;
  EXPECT_TRUE(default_list.Get("keya", &value));
  EXPECT_TRUE(default_list.Remove("keya"));
  EXPECT_FALSE(default_list.Get("keya", &value));
  EXPECT_FALSE(default_list.Remove("keya"));
}

TEST_F(T_Xattr, IsEmpty) {
  EXPECT_TRUE(XattrList().IsEmpty());
  EXPECT_FALSE(default_list.IsEmpty());
  vector<string> keys = default_list.ListKeys();
  for (unsigned i = 0; i < keys.size(); ++i) {
    EXPECT_TRUE(default_list.Remove(keys[i]));
  }
  EXPECT_TRUE(default_list.IsEmpty());
}

// The normal serialization part is tested as part of Deserialize
TEST_F(T_Xattr, SerializeNull) {
  unsigned char *buf;
  unsigned size;
  XattrList empty_list;
  empty_list.Serialize(&buf, &size);
  EXPECT_EQ(NULL, buf);
  EXPECT_EQ(0U, size);
}

TEST_F(T_Xattr, Limits) {
  XattrList large_list;
  string large_value(256, 'a');
  for (unsigned i = 0; i < 256; ++i) {
    char hex[3];
    snprintf(hex, sizeof(hex), "%02x", i);
    string large_key(128, hex[0]);
    large_key += string(128, hex[1]);
    EXPECT_TRUE(large_list.Set(large_key, large_value));
  }
  EXPECT_EQ(256U, large_list.ListKeys().size());
  for (unsigned i = 0; i < 256; ++i) {
    string value;
    char hex[3];
    snprintf(hex, sizeof(hex), "%02x", i);
    string large_key(128, hex[0]);
    large_key += string(128, hex[1]);
    EXPECT_TRUE(large_list.Get(large_key, &value));
    EXPECT_EQ(large_value, value);
  }
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "fnord-base/io/inputstream.h"
#include "fnord-json/flatjsonreader.h"
#include "fnord-json/jsondocument.h"
#include "fnord-json/jsonutil.h"
#include "fnord-json/jsoninputstream.h"
#include "fnord-json/jsonpointer.h"
#include "fnord-base/test/unittest.h"

UNIT_TEST(JSONTest);

using fnord::StringInputStream;
using fnord::json::FlatJSONReader;
using fnord::json::JSONDocument;
using fnord::json::JSONInputStream;
using fnord::json::JSONPointer;
using fnord::json::JSONUtil;

TEST_CASE(JSONTest, TestJSONInputStream, [] () {
  auto json1 = "{ 123: \"fnord\", \"blah\": [ true, false, null, 3.7e-5 ] }";
  JSONInputStream json1_stream(StringInputStream::fromString(json1));

  fnord::json::kTokenType token_type;
  std::string token_str;

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_OBJECT_BEGIN);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_NUMBER);
  EXPECT_EQ(token_str, "123");

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_STRING);
  EXPECT_EQ(token_str, "fnord");

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_STRING);
  EXPECT_EQ(token_str, "blah");

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_ARRAY_BEGIN);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_TRUE);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_FALSE);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_NULL);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_NUMBER);
  EXPECT_EQ(token_str, "3.7e-5");

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_ARRAY_END);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_OBJECT_END);
});

TEST_CASE(JSONTest, TestJSONInputStreamEscaping, [] () {
  auto json1 = "{ 123: \"fno\\\"rd\" }";
  JSONInputStream json1_stream(StringInputStream::fromString(json1));

  fnord::json::kTokenType token_type;
  std::string token_str;

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_OBJECT_BEGIN);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_NUMBER);
  EXPECT_EQ(token_str, "123");

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_STRING);
  EXPECT_EQ(token_str, "fno\"rd");

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_OBJECT_END);
});

TEST_CASE(JSONTest, TestJSONDocumentGet, [] () {
  auto json1 = "{ 123: \"fnord\", \"blah\": [ true, false, null, 3.7e-5 ] }";
  JSONDocument json1_doc(json1);

  EXPECT_EQ(json1_doc.get("/123"), "fnord");
  EXPECT_EQ(json1_doc.get("/blah/0"), "true");
  EXPECT_EQ(json1_doc.get("/blah/1"), "false");
  EXPECT_EQ(json1_doc.get("/blah/2"), "null");
  EXPECT_EQ(json1_doc.get("/blah/3"), "3.7e-5");
});

TEST_CASE(JSONTest, TestJSONDocumentForEach, [] () {
  auto json1 = "{ 123: \"fnord\", \"blah\": [ true, false, null, 3.7e-5 ] }";
  JSONDocument json1_doc(json1);

  int n = 0;
  json1_doc.forEach(JSONPointer("/"), [&n] (const JSONPointer& path) -> bool {
    if (n == 0) { EXPECT_EQ(path.toString(), "/123"); }
    if (n == 1) { EXPECT_EQ(path.toString(), "/blah"); }
    EXPECT_TRUE(n++ < 2);
    return true;
  });

  n = 0;
  json1_doc.forEach(JSONPointer("/blah"), [&n] (
      const JSONPointer& path) -> bool {
    if (n == 0) { EXPECT_EQ(path.toString(), "/blah/0"); }
    if (n == 1) { EXPECT_EQ(path.toString(), "/blah/1"); }
    if (n == 2) { EXPECT_EQ(path.toString(), "/blah/2"); }
    if (n == 3) { EXPECT_EQ(path.toString(), "/blah/3"); }
    EXPECT_TRUE(n++ < 4);
    return true;
  });

  n = 0;
  json1_doc.forEach(JSONPointer("/blah/"), [&n] (
      const JSONPointer& path) -> bool {
    if (n == 0) { EXPECT_EQ(path.toString(), "/blah/0"); }
    if (n == 1) { EXPECT_EQ(path.toString(), "/blah/1"); }
    if (n == 2) { EXPECT_EQ(path.toString(), "/blah/2"); }
    if (n == 3) { EXPECT_EQ(path.toString(), "/blah/3"); }
    EXPECT_TRUE(n++ < 4);
    return true;
  });
});

TEST_CASE(JSONTest, TestJSONPointerEscaping, [] () {
  std::string str1 = "blah~fnord/bar/12~35";
  JSONPointer::escape(&str1);
  EXPECT_EQ(str1, "blah~0fnord~1bar~112~035");
});

typedef std::vector<std::pair<std::string, std::string>> VectorOfStringPairs;

TEST_CASE(JSONTest, TestFlatJSONReader, [] () {
  std::string str1 = "blah~fnord/bar/12~35";
  JSONPointer::escape(&str1);
  EXPECT_EQ(str1, "blah~0fnord~1bar~112~035");

  auto json1 = "{ 123: \"fnord\", \"blah\": [ true, false, null, 3.7e-5 ] }";
  FlatJSONReader json1_reader(
      JSONInputStream(StringInputStream::fromString(json1)));

  VectorOfStringPairs expected;
  expected.emplace_back(std::make_pair("/123", "fnord"));
  expected.emplace_back(std::make_pair("/blah/0", "true"));
  expected.emplace_back(std::make_pair("/blah/1", "false"));
  expected.emplace_back(std::make_pair("/blah/2", "null"));
  expected.emplace_back(std::make_pair("/blah/3", "3.7e-5"));

  int n = 0;
  json1_reader.read([&] (
      const JSONPointer& path,
      const std::string& value) -> bool {
    EXPECT_TRUE(n < expected.size());
    EXPECT_EQ(expected[n].first, path.toString());
    EXPECT_EQ(expected[n].second, value);
    n++;
    return true;
  });
});

TEST_CASE(JSONTest, TestFromJSON, [] () {
  EXPECT_EQ(fnord::json::fromJSON<std::string>("\"fnord\""), "fnord");

  auto json1 = fnord::json::parseJSON(
      "{ 123: \"fnord\", \"blubb\": \"xxx\", \"blah\": [ true, false, null, " \
      "3.7e-5 ] }");

  auto iter = JSONUtil::objectLookup(json1.begin(), json1.end(), "blubb");
  EXPECT_TRUE(iter != json1.end());
  EXPECT_EQ(fnord::json::fromJSON<std::string>(iter, json1.end()), "xxx");

  iter = JSONUtil::objectLookup(json1.begin(), json1.end(), "blah");
  EXPECT_TRUE(iter != json1.end());
  EXPECT_EQ(iter->type, fnord::json::JSON_ARRAY_BEGIN);
  EXPECT_EQ(JSONUtil::arrayLength(iter, json1.end()), 4);

  auto aiter = JSONUtil::arrayLookup(iter, json1.end(), 0);
  EXPECT_EQ(fnord::json::fromJSON<std::string>(aiter, json1.end()), "true");
  aiter = JSONUtil::arrayLookup(iter, json1.end(), 1);
  EXPECT_EQ(fnord::json::fromJSON<std::string>(aiter, json1.end()), "false");
  aiter = JSONUtil::arrayLookup(iter, json1.end(), 2);
  EXPECT_EQ(fnord::json::fromJSON<std::string>(aiter, json1.end()), "null");
  aiter = JSONUtil::arrayLookup(iter, json1.end(), 3);
  EXPECT_EQ(fnord::json::fromJSON<std::string>(aiter, json1.end()), "3.7e-5");
});

TEST_CASE(JSONTest, TestToJSON, [] () {
  fnord::json::JSONObject j1;
  fnord::json::toJSON(std::string("blah"), &j1);

  EXPECT_EQ(j1.size(), 1);
  EXPECT_EQ(j1[0].type, fnord::json::JSON_STRING);
  EXPECT_EQ(j1[0].data, "blah");
});

struct TestMessage {
  std::string a;
  int b;

  template <typename T>
  static void reflect(T* meta) {
    meta->prop(&TestMessage::a, 1, "a", false);
    meta->prop(&TestMessage::b, 2, "b", false);
  }
};

TEST_CASE(JSONTest, TestToFromJSON, [] () {
  TestMessage m1;
  m1.a = "stringdata";
  m1.b = 23;

  auto j1 = fnord::json::parseJSON(fnord::json::toJSONString(m1));
  auto m2 = fnord::json::fromJSON<TestMessage>(j1);

  EXPECT_EQ(m1.a, m2.a);
  EXPECT_EQ(m1.b, m2.b);
});

struct TestStruct {
  fnord::String str;
  fnord::json::JSONObject obj;

  template <typename T>
  static void reflect(T* meta) {
    meta->prop(&TestStruct::str, 1, "str", false);
    meta->prop(&TestStruct::obj, 2, "obj", false);
  };
};

TEST_CASE(JSONTest, TestJSONShouldNotSegfaultOnInvalidInput, [] () {
  EXPECT_EXCEPTION("unbalanced braces", [] {
    auto orig_str = "{ \"str\": \"fnord\", \"obj\": { \"a\": 1, \"b\": 2 ] } }";
    auto obj = fnord::json::fromJSON<TestStruct>(orig_str);
  });
});

TEST_CASE(JSONTest, TestJSONReEncodingViaReflectionWithObject, [] () {
  auto orig_str = "{\"str\":\"fnord\",\"obj\":{\"a\":\"1\",\"b\":\"2\"}}";
  auto obj = fnord::json::fromJSON<TestStruct>(orig_str);
  auto reenc_str = fnord::json::toJSONString(obj);
  EXPECT_EQ(orig_str, reenc_str);
});

/*
TEST_CASE(JSONTest, TestParseJSON, [] () {
  auto json = fnord::json::parseJSON(R"(
    {
       "jsonrpc":"2.0",
       "id":"0",
       "result":[
          {
             "a":"0",
             "b":"c",
             "data":"xxx|bbb|v=3&1,2,4~5,"
          }
       ]
    }
  )");

  EXPECT_EQ(json.size(), 17);
});
*/
<commit_msg>failing json test case<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "fnord-base/io/inputstream.h"
#include "fnord-json/flatjsonreader.h"
#include "fnord-json/jsondocument.h"
#include "fnord-json/jsonutil.h"
#include "fnord-json/jsoninputstream.h"
#include "fnord-json/jsonpointer.h"
#include "fnord-base/test/unittest.h"

UNIT_TEST(JSONTest);

using fnord::StringInputStream;
using fnord::json::FlatJSONReader;
using fnord::json::JSONDocument;
using fnord::json::JSONInputStream;
using fnord::json::JSONPointer;
using fnord::json::JSONUtil;

TEST_CASE(JSONTest, TestJSONInputStream, [] () {
  auto json1 = "{ 123: \"fnord\", \"blah\": [ true, false, null, 3.7e-5 ] }";
  JSONInputStream json1_stream(StringInputStream::fromString(json1));

  fnord::json::kTokenType token_type;
  std::string token_str;

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_OBJECT_BEGIN);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_NUMBER);
  EXPECT_EQ(token_str, "123");

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_STRING);
  EXPECT_EQ(token_str, "fnord");

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_STRING);
  EXPECT_EQ(token_str, "blah");

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_ARRAY_BEGIN);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_TRUE);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_FALSE);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_NULL);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_NUMBER);
  EXPECT_EQ(token_str, "3.7e-5");

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_ARRAY_END);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_OBJECT_END);
});

TEST_CASE(JSONTest, TestJSONInputStreamEscaping, [] () {
  auto json1 = "{ 123: \"fno\\\"rd\" }";
  JSONInputStream json1_stream(StringInputStream::fromString(json1));

  fnord::json::kTokenType token_type;
  std::string token_str;

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_OBJECT_BEGIN);

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_NUMBER);
  EXPECT_EQ(token_str, "123");

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_STRING);
  EXPECT_EQ(token_str, "fno\"rd");

  EXPECT_TRUE(json1_stream.readNextToken(&token_type, &token_str));
  EXPECT_EQ(token_type, fnord::json::JSON_OBJECT_END);
});

TEST_CASE(JSONTest, TestJSONDocumentGet, [] () {
  auto json1 = "{ 123: \"fnord\", \"blah\": [ true, false, null, 3.7e-5 ] }";
  JSONDocument json1_doc(json1);

  EXPECT_EQ(json1_doc.get("/123"), "fnord");
  EXPECT_EQ(json1_doc.get("/blah/0"), "true");
  EXPECT_EQ(json1_doc.get("/blah/1"), "false");
  EXPECT_EQ(json1_doc.get("/blah/2"), "null");
  EXPECT_EQ(json1_doc.get("/blah/3"), "3.7e-5");
});

TEST_CASE(JSONTest, TestJSONDocumentForEach, [] () {
  auto json1 = "{ 123: \"fnord\", \"blah\": [ true, false, null, 3.7e-5 ] }";
  JSONDocument json1_doc(json1);

  int n = 0;
  json1_doc.forEach(JSONPointer("/"), [&n] (const JSONPointer& path) -> bool {
    if (n == 0) { EXPECT_EQ(path.toString(), "/123"); }
    if (n == 1) { EXPECT_EQ(path.toString(), "/blah"); }
    EXPECT_TRUE(n++ < 2);
    return true;
  });

  n = 0;
  json1_doc.forEach(JSONPointer("/blah"), [&n] (
      const JSONPointer& path) -> bool {
    if (n == 0) { EXPECT_EQ(path.toString(), "/blah/0"); }
    if (n == 1) { EXPECT_EQ(path.toString(), "/blah/1"); }
    if (n == 2) { EXPECT_EQ(path.toString(), "/blah/2"); }
    if (n == 3) { EXPECT_EQ(path.toString(), "/blah/3"); }
    EXPECT_TRUE(n++ < 4);
    return true;
  });

  n = 0;
  json1_doc.forEach(JSONPointer("/blah/"), [&n] (
      const JSONPointer& path) -> bool {
    if (n == 0) { EXPECT_EQ(path.toString(), "/blah/0"); }
    if (n == 1) { EXPECT_EQ(path.toString(), "/blah/1"); }
    if (n == 2) { EXPECT_EQ(path.toString(), "/blah/2"); }
    if (n == 3) { EXPECT_EQ(path.toString(), "/blah/3"); }
    EXPECT_TRUE(n++ < 4);
    return true;
  });
});

TEST_CASE(JSONTest, TestJSONPointerEscaping, [] () {
  std::string str1 = "blah~fnord/bar/12~35";
  JSONPointer::escape(&str1);
  EXPECT_EQ(str1, "blah~0fnord~1bar~112~035");
});

typedef std::vector<std::pair<std::string, std::string>> VectorOfStringPairs;

TEST_CASE(JSONTest, TestFlatJSONReader, [] () {
  std::string str1 = "blah~fnord/bar/12~35";
  JSONPointer::escape(&str1);
  EXPECT_EQ(str1, "blah~0fnord~1bar~112~035");

  auto json1 = "{ 123: \"fnord\", \"blah\": [ true, false, null, 3.7e-5 ] }";
  FlatJSONReader json1_reader(
      JSONInputStream(StringInputStream::fromString(json1)));

  VectorOfStringPairs expected;
  expected.emplace_back(std::make_pair("/123", "fnord"));
  expected.emplace_back(std::make_pair("/blah/0", "true"));
  expected.emplace_back(std::make_pair("/blah/1", "false"));
  expected.emplace_back(std::make_pair("/blah/2", "null"));
  expected.emplace_back(std::make_pair("/blah/3", "3.7e-5"));

  int n = 0;
  json1_reader.read([&] (
      const JSONPointer& path,
      const std::string& value) -> bool {
    EXPECT_TRUE(n < expected.size());
    EXPECT_EQ(expected[n].first, path.toString());
    EXPECT_EQ(expected[n].second, value);
    n++;
    return true;
  });
});

TEST_CASE(JSONTest, TestFromJSON, [] () {
  EXPECT_EQ(fnord::json::fromJSON<std::string>("\"fnord\""), "fnord");

  auto json1 = fnord::json::parseJSON(
      "{ 123: \"fnord\", \"blubb\": \"xxx\", \"blah\": [ true, false, null, " \
      "3.7e-5 ] }");

  auto iter = JSONUtil::objectLookup(json1.begin(), json1.end(), "blubb");
  EXPECT_TRUE(iter != json1.end());
  EXPECT_EQ(fnord::json::fromJSON<std::string>(iter, json1.end()), "xxx");

  iter = JSONUtil::objectLookup(json1.begin(), json1.end(), "blah");
  EXPECT_TRUE(iter != json1.end());
  EXPECT_EQ(iter->type, fnord::json::JSON_ARRAY_BEGIN);
  EXPECT_EQ(JSONUtil::arrayLength(iter, json1.end()), 4);

  auto aiter = JSONUtil::arrayLookup(iter, json1.end(), 0);
  EXPECT_EQ(fnord::json::fromJSON<std::string>(aiter, json1.end()), "true");
  aiter = JSONUtil::arrayLookup(iter, json1.end(), 1);
  EXPECT_EQ(fnord::json::fromJSON<std::string>(aiter, json1.end()), "false");
  aiter = JSONUtil::arrayLookup(iter, json1.end(), 2);
  EXPECT_EQ(fnord::json::fromJSON<std::string>(aiter, json1.end()), "null");
  aiter = JSONUtil::arrayLookup(iter, json1.end(), 3);
  EXPECT_EQ(fnord::json::fromJSON<std::string>(aiter, json1.end()), "3.7e-5");
});

TEST_CASE(JSONTest, TestToJSON, [] () {
  fnord::json::JSONObject j1;
  fnord::json::toJSON(std::string("blah"), &j1);

  EXPECT_EQ(j1.size(), 1);
  EXPECT_EQ(j1[0].type, fnord::json::JSON_STRING);
  EXPECT_EQ(j1[0].data, "blah");
});

struct TestMessage {
  std::string a;
  int b;

  template <typename T>
  static void reflect(T* meta) {
    meta->prop(&TestMessage::a, 1, "a", false);
    meta->prop(&TestMessage::b, 2, "b", false);
  }
};

TEST_CASE(JSONTest, TestToFromJSON, [] () {
  TestMessage m1;
  m1.a = "stringdata";
  m1.b = 23;

  auto j1 = fnord::json::parseJSON(fnord::json::toJSONString(m1));
  auto m2 = fnord::json::fromJSON<TestMessage>(j1);

  EXPECT_EQ(m1.a, m2.a);
  EXPECT_EQ(m1.b, m2.b);
});

struct TestStruct {
  fnord::String str;
  fnord::json::JSONObject obj;

  template <typename T>
  static void reflect(T* meta) {
    meta->prop(&TestStruct::str, 1, "str", false);
    meta->prop(&TestStruct::obj, 2, "obj", false);
  };
};

TEST_CASE(JSONTest, TestJSONShouldNotSegfaultOnInvalidInput, [] () {
  EXPECT_EXCEPTION("unbalanced braces", [] {
    auto orig_str = "{ \"str\": \"fnord\", \"obj\": { \"a\": 1, \"b\": 2 ] } }";
    auto obj = fnord::json::fromJSON<TestStruct>(orig_str);
  });
});

TEST_CASE(JSONTest, TestJSONReEncodingViaReflectionWithObject, [] () {
  auto orig_str = "{\"str\":\"fnord\",\"obj\":{\"a\":\"1\",\"b\":\"2\"}}";
  auto obj = fnord::json::fromJSON<TestStruct>(orig_str);
  auto reenc_str = fnord::json::toJSONString(obj);
  EXPECT_EQ(orig_str, reenc_str);
});

struct TestJSONObject {
  std::string data;

  template <typename T>
  static void reflect(T* meta) {
    meta->prop(&TestJSONObject::data, 1, "data", false);
  }
};

TEST_CASE(JSONTest, TestJSONReencoding1, [] () {
  auto orig_str = R"({"customer":"xxx","docid":{"set_id":"p","item_id":"123"},"attributes":{"title~en":"12- blubb silver version","description~en":"925 blah blahb blah -- \"12\" represents 12 different chinese zodiac sign animals 鼠 Rat is symbol of Charm  those who born in 1948、1960、1972、1984 、1996 and 2008 are belonged to Rat  product description: it is a pendant with 2 faces 1 face is shinny well-polished silver surface the other face is matt look finishing with a raw feeling therefore, this big pendant can be wear in both sides to match your apparel!  the pendant is linked by a 100cm/ 40 inch long silver plated chain.  pendant size: 8.5cm x 7cm, about 15 gr.  the necklace would be received with our gift packing especially for rat @\"12\" series!!  ******************************************************  you are welcome to visit my web-site","category2":"999"}})";
  auto doc = fnord::json::parseJSON(orig_str);
  TestJSONObject obj;
  obj.data = fnord::json::toJSONString(doc);
  auto obj_json = fnord::json::toJSONString(obj);
  fnord::iputs("json_str: $0", obj_json);
  auto obj2 = fnord::json::fromJSON<TestJSONObject>(obj_json);
  fnord::iputs("json_str: $0", obj2.data);
  EXPECT_EQ(obj2.data, orig_str);
});

/*
TEST_CASE(JSONTest, TestParseJSON, [] () {
  auto json = fnord::json::parseJSON(R"(
    {
       "jsonrpc":"2.0",
       "id":"0",
       "result":[
          {
             "a":"0",
             "b":"c",
             "data":"xxx|bbb|v=3&1,2,4~5,"
          }
       ]
    }
  )");

  EXPECT_EQ(json.size(), 17);
});
*/
<|endoftext|>


<commit_before>//--------------------------------------------------------------------------------
//	File		: MLApp.cpp
//	Description	:
//	Author		: Chang, Hsiao-Yi
//
//	Copyright (c) 2014-2015. All rights reserved.
//	https://github.com/hsiaoyi/Melo
//--------------------------------------------------------------------------------

#include <iostream>
#include "MLApp.h"

//--------------------------------------------------------------------------------
using namespace std;
USING_NS_CC;

//--------------------------------------------------------------------------------
MLApp::MLApp()
{
	Director::getInstance()->SetMeloMain(&MLApp::main);
};

//--------------------------------------------------------------------------------
// note: this funciton called beford actual drawing every frame
void MLApp::main()
{
	// todo:
	// process all child CBs
	MLLOG("---MELO MAIN LOOP---");
}
<commit_msg>revert test<commit_after>//--------------------------------------------------------------------------------
//	File		: MLApp.cpp
//	Description	:
//	Author		: Chang, Hsiao-Yi
//
//	Copyright (c) 2014. All rights reserved.
//	https://github.com/hsiaoyi/Melo
//--------------------------------------------------------------------------------

#include <iostream>
#include "MLApp.h"

//--------------------------------------------------------------------------------
using namespace std;
USING_NS_CC;

//--------------------------------------------------------------------------------
MLApp::MLApp()
{
	Director::getInstance()->SetMeloMain(&MLApp::main);
};

//--------------------------------------------------------------------------------
// note: this funciton called beford actual drawing every frame
void MLApp::main()
{
	// todo:
	// process all child CBs
	MLLOG("---MELO MAIN LOOP---");
}
<|endoftext|>