<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Interpreter/ValuePrinter.h"

#include "cling/Interpreter/CValuePrinter.h"
#include "cling/Interpreter/ValuePrinterInfo.h"
#include "cling/Interpreter/StoredValueRef.h"
#include "cling/Interpreter/Value.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"

#include "llvm/Support/raw_ostream.h"
#include "llvm/ExecutionEngine/GenericValue.h"

#include <string>
#include <sstream>
#include <cstdio>

// Fragment copied from LLVM's raw_ostream.cpp
#if defined(_MSC_VER)
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif
#else
//#if defined(HAVE_UNISTD_H)
# include <unistd.h>
//#endif
#endif

using namespace cling;

// Implements the CValuePrinter interface.
extern "C" void cling_PrintValue(void* /*clang::Expr**/ E,
                      void* /*clang::ASTContext**/ C,
                      const void* value) {
  clang::Expr* Exp = (clang::Expr*)E;
  clang::ASTContext* Context = (clang::ASTContext*)C;
  ValuePrinterInfo VPI(Exp->getType(), Context);

  // We need stream that doesn't close its file descriptor, thus we are not
  // using llvm::outs. Keeping file descriptor open we will be able to use
  // the results in pipes (Savannah #99234).
  llvm::raw_fd_ostream outs (STDOUT_FILENO, /*ShouldClose*/false);

  valuePrinterInternal::flushToStream(outs, printType(value, value, VPI)
                                      + printValue(value, value, VPI));
}

static void StreamValue(llvm::raw_ostream& o, const void* const p,
                        const ValuePrinterInfo& VPI);

static void StreamChar(llvm::raw_ostream& o, const char v) {
  if (isprint(v))
    o << '"' << v << "\"";
  else {
    o << "\\0x";
    o.write_hex(v);
  }
}

static void StreamCharPtr(llvm::raw_ostream& o, const char* const v) {
  if (!v) {
    o << "<<<NULL>>>";
    return;
  }
  o << '"';
  const char* p = v;
  for (;*p && p - v < 128; ++p) {
    o << *p;
  }
  if (*p) o << "\"...";
  else o << "\"";
}

static void StreamRef(llvm::raw_ostream& o, const void* v,
                      const ValuePrinterInfo& VPI) {
  const clang::ReferenceType* RTy
    = llvm::dyn_cast<clang::ReferenceType>(VPI.getType().getTypePtr());
  ValuePrinterInfo VPIRefed(RTy->getPointeeType(), VPI.getASTContext());
  StreamValue(o, v, VPIRefed);
}

static void StreamPtr(llvm::raw_ostream& o, const void* v) {
  o << v;
}

static void StreamArr(llvm::raw_ostream& o, const void* p,
                      const ValuePrinterInfo& VPI) {
  const clang::QualType& Ty = VPI.getType();
  clang::ASTContext& C = *VPI.getASTContext();
  const clang::ArrayType* ArrTy = Ty->getAsArrayTypeUnsafe();
  clang::QualType ElementTy = ArrTy->getElementType();
  if (ElementTy->isCharType())
    StreamCharPtr(o, (const char*)p);
  else if (Ty->isConstantArrayType()) {
    // Stream a constant array by streaming up to 5 elements.
    const clang::ConstantArrayType* CArrTy
      = C.getAsConstantArrayType(Ty);
    const llvm::APInt& APSize = CArrTy->getSize();
    size_t ElBytes = C.getTypeSize(ElementTy) / C.getCharWidth();
    size_t Size = (size_t)APSize.getZExtValue();
    o << "{ ";
    ValuePrinterInfo ElVPI(ElementTy, &C);
    for (size_t i = 0; i < Size; ++i) {
      StreamValue(o, ((const char*)p) + i * ElBytes, ElVPI);
      if (i + 1 < Size) {
        if (i == 4) {
          o << "...";
          break;
        }
        else o << ", ";
      }
    }
    o << " }";
  } else
    StreamPtr(o, p);
}

static void StreamFunction(llvm::raw_ostream& o, const void* addr,
                           ValuePrinterInfo VPI) {
  o << "Function @" << addr << '\n';

  const clang::DeclRefExpr* DeclRefExp
    = llvm::dyn_cast_or_null<clang::DeclRefExpr>(VPI.getExpr());
  const clang::FunctionDecl* FD = 0;
  if (DeclRefExp)
    FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(DeclRefExp->getDecl());
  if (FD) {
    clang::SourceRange SRange = FD->getSourceRange();
    const char* cBegin = 0;
    const char* cEnd = 0;
    bool Invalid;
    if (SRange.isValid()) {
      clang::SourceManager& SM = VPI.getASTContext()->getSourceManager();
      clang::SourceLocation LocBegin = SRange.getBegin();
      LocBegin = SM.getExpansionRange(LocBegin).first;
      o << "  at " << SM.getFilename(LocBegin);
      unsigned LineNo = SM.getSpellingLineNumber(LocBegin, &Invalid);
      if (!Invalid)
        o << ':' << LineNo;
      o << ":\n";
      bool Invalid = false;
      cBegin = SM.getCharacterData(LocBegin, &Invalid);
      if (!Invalid) {
        clang::SourceLocation LocEnd = SRange.getEnd();
        LocEnd = SM.getExpansionRange(LocEnd).second;
        cEnd = SM.getCharacterData(LocEnd, &Invalid);
        if (Invalid)
          cBegin = 0;
      } else {
        cBegin = 0;
      }
    }
    if (cBegin && cEnd && cEnd > cBegin && cEnd - cBegin < 16 * 1024) {
      o << llvm::StringRef(cBegin, cEnd - cBegin + 1);
    } else {
      const clang::FunctionDecl* FDef;
      if (FD->hasBody(FDef))
        FD = FDef;
      FD->print(o);
      //const clang::FunctionDecl* FD
      //  = llvm::cast<const clang::FunctionType>(Ty)->getDecl();
    }
  } else {
    o << ":\n";
    // type-based printing:
    VPI.getType().print(o, VPI.getASTContext()->getPrintingPolicy());
  }
  // type-based print() never and decl-based print() sometimes does not include
  // a final newline:
  o << '\n';
}

static void StreamLongDouble(llvm::raw_ostream& o, const Value* value,
                             clang::ASTContext& C) {
  llvm::APFloat LDbl(C.getFloatTypeSemantics(value->getClangType()),
                     value->getGV().IntVal);
  llvm::SmallString<24> Buf;
  LDbl.toString(Buf);
  o << Buf << 'L';
}

static void StreamClingValue(llvm::raw_ostream& o, const Value* value,
                             clang::ASTContext& C) {
  if (!value || !value->isValid()) {
    o << "<<<invalid>>> @" << value;
  } else {
    o << "boxes [";
    o << "("
      << value->getClangType().getAsString(C.getPrintingPolicy())
      << ") ";
    clang::QualType valType = value->getClangType().getDesugaredType(C);
    if (C.hasSameType(valType, C.LongDoubleTy))
      StreamLongDouble(o, value, C);
    else if (valType->isFloatingType())
      o << value->getGV().DoubleVal;
    else if (valType->isIntegerType())
      o << value->getGV().IntVal.getSExtValue();
    else if (valType->isBooleanType())
      o << value->getGV().IntVal.getBoolValue();
    else
      StreamValue(o, value->getGV().PointerVal,
                  ValuePrinterInfo(valType, &C));
    o << "]";
  }
}

static void StreamObj(llvm::raw_ostream& o, const void* v,
                      const ValuePrinterInfo& VPI) {
  const clang::Type* Ty = VPI.getType().getTypePtr();
  if (clang::CXXRecordDecl* CXXRD = Ty->getAsCXXRecordDecl()) {
    std::string QualName = CXXRD->getQualifiedNameAsString();
    if (QualName == "cling::StoredValueRef"){
      valuePrinterInternal::StreamStoredValueRef(o, (const StoredValueRef*)v,
                                                 *VPI.getASTContext());
      return;
    } else if (QualName == "cling::Value") {
      StreamClingValue(o, (const Value*)v, *VPI.getASTContext());
      return;
    }
  } // if CXXRecordDecl

  // TODO: Print the object members.
  o << "@" << v;
}

static void StreamValue(llvm::raw_ostream& o, const void* const p,
                        const ValuePrinterInfo& VPI) {
  clang::ASTContext& C = *VPI.getASTContext();
  clang::QualType Ty = VPI.getType().getDesugaredType(C);
  if (const clang::BuiltinType *BT
           = llvm::dyn_cast<clang::BuiltinType>(Ty.getCanonicalType())) {
    switch (BT->getKind()) {
    case clang::BuiltinType::Bool:
      if (*(const bool*)p) o << "true";
      else o << "false"; break;
    case clang::BuiltinType::Char_U:
    case clang::BuiltinType::UChar:
    case clang::BuiltinType::Char_S:
    case clang::BuiltinType::SChar:  StreamChar(o, *(const char*)p); break;
    case clang::BuiltinType::Short:  o << *(const short*)p; break;
    case clang::BuiltinType::UShort:
      o << *(const unsigned short*)p;
      break;
    case clang::BuiltinType::Int:    o << *(const int*)p; break;
    case clang::BuiltinType::UInt:
      o << *(const unsigned int*)p;
      break;
    case clang::BuiltinType::Long:   o << *(const long*)p; break;
    case clang::BuiltinType::ULong:
      o << *(const unsigned long*)p;
      break;
    case clang::BuiltinType::LongLong:
      o << *(const long long*)p;
      break;
    case clang::BuiltinType::ULongLong:
      o << *(const unsigned long long*)p;
      break;
    case clang::BuiltinType::Float:  o << *(const float*)p; break;
    case clang::BuiltinType::Double: o << *(const double*)p; break;
    case clang::BuiltinType::LongDouble: {
      std::stringstream ssLD;
      ssLD << *(const long double*)p;
      o << ssLD.str() << 'L'; break;
    }
    default:
      StreamObj(o, p, ValuePrinterInfo(Ty, &C));
    }
  }
  else if (Ty.getAsString().compare("class std::basic_string<char>") == 0
           || Ty.getAsString().compare("class std::__1::basic_string<char, "
                                       "struct std::__1::char_traits<char>, "
                                       "class std::__1::allocator<char> >")
           == 0) {
    StreamObj(o, p, ValuePrinterInfo(Ty, &C));
    o << " "; // force a space
    o <<"c_str: ";
    StreamCharPtr(o, ((const char*) (*(const std::string*)p).c_str()));
  }
  else if (Ty->isEnumeralType()) {
    clang::EnumDecl* ED = Ty->getAs<clang::EnumType>()->getDecl();
    uint64_t value = *(const uint64_t*)p;
    bool IsFirst = true;
    llvm::APSInt ValAsAPSInt = C.MakeIntValue(value, Ty);
    for (clang::EnumDecl::enumerator_iterator I = ED->enumerator_begin(),
           E = ED->enumerator_end(); I != E; ++I) {
      if (I->getInitVal() == ValAsAPSInt) {
        if (!IsFirst) {
          o << " ? ";
        }
        o << "(" << I->getQualifiedNameAsString() << ")";
        IsFirst = false;
      }
    }
    o << " : (int) " << ValAsAPSInt.toString(/*Radix = */10);
  }
  else if (Ty->isReferenceType())
    StreamRef(o, p, VPI);
  else if (Ty->isPointerType()) {
    clang::QualType PointeeTy = Ty->getPointeeType();
    if (PointeeTy->isCharType())
      StreamCharPtr(o, (const char*)p);
    else
      StreamPtr(o, p);
  }
  else if (Ty->isArrayType())
    StreamArr(o, p, ValuePrinterInfo(Ty, &C));
  else if (Ty->isFunctionType())
     StreamFunction(o, p, VPI);
  else
    StreamObj(o, p, ValuePrinterInfo(Ty, &C));
}

namespace cling {
namespace valuePrinterInternal {
  std::string printValue_Default(const void* const p,
                                 const ValuePrinterInfo& VPI) {
    std::string buf;
    {
      llvm::raw_string_ostream o(buf);
      StreamValue(o, p, VPI);
    }
    return buf;
  }

  std::string printType_Default(const ValuePrinterInfo& VPI) {
    std::string buf;
    {
      llvm::raw_string_ostream o(buf);
      o << "(";
      o << VPI.getType().getAsString();
      o << ") ";
    }
    return buf;
  }

  void StreamStoredValueRef(llvm::raw_ostream& o,
                            const StoredValueRef* VR,
                            clang::ASTContext& C) {
    if (VR->isValid()) {
      StreamClingValue(o, &VR->get(), C);
    } else {
      o << "<<<invalid>>> @" << VR;
    }
  }

  void flushToStream(llvm::raw_ostream& o, const std::string& s) {
    // We want to keep stdout and o in sync if o is different from stdout.
    fflush(stdout);
    o << s;
    o.flush();
  }
} // end namespace valuePrinterInternal
} // end namespace cling
<commit_msg>Support new name of std::string in libc++.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Interpreter/ValuePrinter.h"

#include "cling/Interpreter/CValuePrinter.h"
#include "cling/Interpreter/ValuePrinterInfo.h"
#include "cling/Interpreter/StoredValueRef.h"
#include "cling/Interpreter/Value.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"

#include "llvm/Support/raw_ostream.h"
#include "llvm/ExecutionEngine/GenericValue.h"

#include <string>
#include <sstream>
#include <cstdio>

// Fragment copied from LLVM's raw_ostream.cpp
#if defined(_MSC_VER)
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif
#else
//#if defined(HAVE_UNISTD_H)
# include <unistd.h>
//#endif
#endif

using namespace cling;

// Implements the CValuePrinter interface.
extern "C" void cling_PrintValue(void* /*clang::Expr**/ E,
                      void* /*clang::ASTContext**/ C,
                      const void* value) {
  clang::Expr* Exp = (clang::Expr*)E;
  clang::ASTContext* Context = (clang::ASTContext*)C;
  ValuePrinterInfo VPI(Exp->getType(), Context);

  // We need stream that doesn't close its file descriptor, thus we are not
  // using llvm::outs. Keeping file descriptor open we will be able to use
  // the results in pipes (Savannah #99234).
  llvm::raw_fd_ostream outs (STDOUT_FILENO, /*ShouldClose*/false);

  valuePrinterInternal::flushToStream(outs, printType(value, value, VPI)
                                      + printValue(value, value, VPI));
}

static void StreamValue(llvm::raw_ostream& o, const void* const p,
                        const ValuePrinterInfo& VPI);

static void StreamChar(llvm::raw_ostream& o, const char v) {
  if (isprint(v))
    o << '"' << v << "\"";
  else {
    o << "\\0x";
    o.write_hex(v);
  }
}

static void StreamCharPtr(llvm::raw_ostream& o, const char* const v) {
  if (!v) {
    o << "<<<NULL>>>";
    return;
  }
  o << '"';
  const char* p = v;
  for (;*p && p - v < 128; ++p) {
    o << *p;
  }
  if (*p) o << "\"...";
  else o << "\"";
}

static void StreamRef(llvm::raw_ostream& o, const void* v,
                      const ValuePrinterInfo& VPI) {
  const clang::ReferenceType* RTy
    = llvm::dyn_cast<clang::ReferenceType>(VPI.getType().getTypePtr());
  ValuePrinterInfo VPIRefed(RTy->getPointeeType(), VPI.getASTContext());
  StreamValue(o, v, VPIRefed);
}

static void StreamPtr(llvm::raw_ostream& o, const void* v) {
  o << v;
}

static void StreamArr(llvm::raw_ostream& o, const void* p,
                      const ValuePrinterInfo& VPI) {
  const clang::QualType& Ty = VPI.getType();
  clang::ASTContext& C = *VPI.getASTContext();
  const clang::ArrayType* ArrTy = Ty->getAsArrayTypeUnsafe();
  clang::QualType ElementTy = ArrTy->getElementType();
  if (ElementTy->isCharType())
    StreamCharPtr(o, (const char*)p);
  else if (Ty->isConstantArrayType()) {
    // Stream a constant array by streaming up to 5 elements.
    const clang::ConstantArrayType* CArrTy
      = C.getAsConstantArrayType(Ty);
    const llvm::APInt& APSize = CArrTy->getSize();
    size_t ElBytes = C.getTypeSize(ElementTy) / C.getCharWidth();
    size_t Size = (size_t)APSize.getZExtValue();
    o << "{ ";
    ValuePrinterInfo ElVPI(ElementTy, &C);
    for (size_t i = 0; i < Size; ++i) {
      StreamValue(o, ((const char*)p) + i * ElBytes, ElVPI);
      if (i + 1 < Size) {
        if (i == 4) {
          o << "...";
          break;
        }
        else o << ", ";
      }
    }
    o << " }";
  } else
    StreamPtr(o, p);
}

static void StreamFunction(llvm::raw_ostream& o, const void* addr,
                           ValuePrinterInfo VPI) {
  o << "Function @" << addr << '\n';

  const clang::DeclRefExpr* DeclRefExp
    = llvm::dyn_cast_or_null<clang::DeclRefExpr>(VPI.getExpr());
  const clang::FunctionDecl* FD = 0;
  if (DeclRefExp)
    FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(DeclRefExp->getDecl());
  if (FD) {
    clang::SourceRange SRange = FD->getSourceRange();
    const char* cBegin = 0;
    const char* cEnd = 0;
    bool Invalid;
    if (SRange.isValid()) {
      clang::SourceManager& SM = VPI.getASTContext()->getSourceManager();
      clang::SourceLocation LocBegin = SRange.getBegin();
      LocBegin = SM.getExpansionRange(LocBegin).first;
      o << "  at " << SM.getFilename(LocBegin);
      unsigned LineNo = SM.getSpellingLineNumber(LocBegin, &Invalid);
      if (!Invalid)
        o << ':' << LineNo;
      o << ":\n";
      bool Invalid = false;
      cBegin = SM.getCharacterData(LocBegin, &Invalid);
      if (!Invalid) {
        clang::SourceLocation LocEnd = SRange.getEnd();
        LocEnd = SM.getExpansionRange(LocEnd).second;
        cEnd = SM.getCharacterData(LocEnd, &Invalid);
        if (Invalid)
          cBegin = 0;
      } else {
        cBegin = 0;
      }
    }
    if (cBegin && cEnd && cEnd > cBegin && cEnd - cBegin < 16 * 1024) {
      o << llvm::StringRef(cBegin, cEnd - cBegin + 1);
    } else {
      const clang::FunctionDecl* FDef;
      if (FD->hasBody(FDef))
        FD = FDef;
      FD->print(o);
      //const clang::FunctionDecl* FD
      //  = llvm::cast<const clang::FunctionType>(Ty)->getDecl();
    }
  } else {
    o << ":\n";
    // type-based printing:
    VPI.getType().print(o, VPI.getASTContext()->getPrintingPolicy());
  }
  // type-based print() never and decl-based print() sometimes does not include
  // a final newline:
  o << '\n';
}

static void StreamLongDouble(llvm::raw_ostream& o, const Value* value,
                             clang::ASTContext& C) {
  llvm::APFloat LDbl(C.getFloatTypeSemantics(value->getClangType()),
                     value->getGV().IntVal);
  llvm::SmallString<24> Buf;
  LDbl.toString(Buf);
  o << Buf << 'L';
}

static void StreamClingValue(llvm::raw_ostream& o, const Value* value,
                             clang::ASTContext& C) {
  if (!value || !value->isValid()) {
    o << "<<<invalid>>> @" << value;
  } else {
    o << "boxes [";
    o << "("
      << value->getClangType().getAsString(C.getPrintingPolicy())
      << ") ";
    clang::QualType valType = value->getClangType().getDesugaredType(C);
    if (C.hasSameType(valType, C.LongDoubleTy))
      StreamLongDouble(o, value, C);
    else if (valType->isFloatingType())
      o << value->getGV().DoubleVal;
    else if (valType->isIntegerType())
      o << value->getGV().IntVal.getSExtValue();
    else if (valType->isBooleanType())
      o << value->getGV().IntVal.getBoolValue();
    else
      StreamValue(o, value->getGV().PointerVal,
                  ValuePrinterInfo(valType, &C));
    o << "]";
  }
}

static void StreamObj(llvm::raw_ostream& o, const void* v,
                      const ValuePrinterInfo& VPI) {
  const clang::Type* Ty = VPI.getType().getTypePtr();
  if (clang::CXXRecordDecl* CXXRD = Ty->getAsCXXRecordDecl()) {
    std::string QualName = CXXRD->getQualifiedNameAsString();
    if (QualName == "cling::StoredValueRef"){
      valuePrinterInternal::StreamStoredValueRef(o, (const StoredValueRef*)v,
                                                 *VPI.getASTContext());
      return;
    } else if (QualName == "cling::Value") {
      StreamClingValue(o, (const Value*)v, *VPI.getASTContext());
      return;
    }
  } // if CXXRecordDecl

  // TODO: Print the object members.
  o << "@" << v;
}

static void StreamValue(llvm::raw_ostream& o, const void* const p,
                        const ValuePrinterInfo& VPI) {
  clang::ASTContext& C = *VPI.getASTContext();
  clang::QualType Ty = VPI.getType().getDesugaredType(C);
  if (const clang::BuiltinType *BT
           = llvm::dyn_cast<clang::BuiltinType>(Ty.getCanonicalType())) {
    switch (BT->getKind()) {
    case clang::BuiltinType::Bool:
      if (*(const bool*)p) o << "true";
      else o << "false"; break;
    case clang::BuiltinType::Char_U:
    case clang::BuiltinType::UChar:
    case clang::BuiltinType::Char_S:
    case clang::BuiltinType::SChar:  StreamChar(o, *(const char*)p); break;
    case clang::BuiltinType::Short:  o << *(const short*)p; break;
    case clang::BuiltinType::UShort:
      o << *(const unsigned short*)p;
      break;
    case clang::BuiltinType::Int:    o << *(const int*)p; break;
    case clang::BuiltinType::UInt:
      o << *(const unsigned int*)p;
      break;
    case clang::BuiltinType::Long:   o << *(const long*)p; break;
    case clang::BuiltinType::ULong:
      o << *(const unsigned long*)p;
      break;
    case clang::BuiltinType::LongLong:
      o << *(const long long*)p;
      break;
    case clang::BuiltinType::ULongLong:
      o << *(const unsigned long long*)p;
      break;
    case clang::BuiltinType::Float:  o << *(const float*)p; break;
    case clang::BuiltinType::Double: o << *(const double*)p; break;
    case clang::BuiltinType::LongDouble: {
      std::stringstream ssLD;
      ssLD << *(const long double*)p;
      o << ssLD.str() << 'L'; break;
    }
    default:
      StreamObj(o, p, ValuePrinterInfo(Ty, &C));
    }
  }
  else if (Ty.getAsString().compare("class std::basic_string<char>") == 0
           || Ty.getAsString().compare("class std::__1::basic_string<char, "
                                       "struct std::__1::char_traits<char>, "
                                       "class std::__1::allocator<char> >") == 0
           || Ty.getAsString().compare("class std::__1::basic_string<char>")
           == 0) {
    StreamObj(o, p, ValuePrinterInfo(Ty, &C));
    o << " "; // force a space
    o <<"c_str: ";
    StreamCharPtr(o, ((const char*) (*(const std::string*)p).c_str()));
  }
  else if (Ty->isEnumeralType()) {
    clang::EnumDecl* ED = Ty->getAs<clang::EnumType>()->getDecl();
    uint64_t value = *(const uint64_t*)p;
    bool IsFirst = true;
    llvm::APSInt ValAsAPSInt = C.MakeIntValue(value, Ty);
    for (clang::EnumDecl::enumerator_iterator I = ED->enumerator_begin(),
           E = ED->enumerator_end(); I != E; ++I) {
      if (I->getInitVal() == ValAsAPSInt) {
        if (!IsFirst) {
          o << " ? ";
        }
        o << "(" << I->getQualifiedNameAsString() << ")";
        IsFirst = false;
      }
    }
    o << " : (int) " << ValAsAPSInt.toString(/*Radix = */10);
  }
  else if (Ty->isReferenceType())
    StreamRef(o, p, VPI);
  else if (Ty->isPointerType()) {
    clang::QualType PointeeTy = Ty->getPointeeType();
    if (PointeeTy->isCharType())
      StreamCharPtr(o, (const char*)p);
    else
      StreamPtr(o, p);
  }
  else if (Ty->isArrayType())
    StreamArr(o, p, ValuePrinterInfo(Ty, &C));
  else if (Ty->isFunctionType())
     StreamFunction(o, p, VPI);
  else
    StreamObj(o, p, ValuePrinterInfo(Ty, &C));
}

namespace cling {
namespace valuePrinterInternal {
  std::string printValue_Default(const void* const p,
                                 const ValuePrinterInfo& VPI) {
    std::string buf;
    {
      llvm::raw_string_ostream o(buf);
      StreamValue(o, p, VPI);
    }
    return buf;
  }

  std::string printType_Default(const ValuePrinterInfo& VPI) {
    std::string buf;
    {
      llvm::raw_string_ostream o(buf);
      o << "(";
      o << VPI.getType().getAsString();
      o << ") ";
    }
    return buf;
  }

  void StreamStoredValueRef(llvm::raw_ostream& o,
                            const StoredValueRef* VR,
                            clang::ASTContext& C) {
    if (VR->isValid()) {
      StreamClingValue(o, &VR->get(), C);
    } else {
      o << "<<<invalid>>> @" << VR;
    }
  }

  void flushToStream(llvm::raw_ostream& o, const std::string& s) {
    // We want to keep stdout and o in sync if o is different from stdout.
    fflush(stdout);
    o << s;
    o.flush();
  }
} // end namespace valuePrinterInternal
} // end namespace cling
<|endoftext|>


<commit_before>#include "thrusttest/testframework.h"
#include "thrusttest/exceptions.h"

#include <cuda_runtime.h>
#include <iostream>
#include <cstdlib>

void UnitTestDriver::register_test(UnitTest *test)
{
    UnitTestDriver::s_driver()._test_list.push_back(test);
}

UnitTest::UnitTest(const char * _name) : name(_name)
{
  UnitTestDriver::s_driver().register_test(this);
}

bool UnitTestDriver::run_tests(const std::vector<UnitTest *> &tests_to_run, const bool verbose)
{
    bool any_failed = false;

    std::cout << "Running " << tests_to_run.size() << " unit tests." << std::endl;

    std::vector< std::pair<UnitTest *,thrusttest::UnitTestFailure> >      test_failures;
    std::vector< std::pair<UnitTest *,thrusttest::UnitTestKnownFailure> > test_known_failures;
    std::vector< std::pair<UnitTest *,thrusttest::UnitTestError>   >      test_errors;
    std::vector< UnitTest * >                                              test_exceptions;

    cudaError_t error = cudaGetLastError();
    if(error){
        std::cerr << "[ERROR] CUDA Error detected before running tests: [";
        std::cerr << std::string(cudaGetErrorString(error));
        std::cerr << "]" << std::endl;
        exit(EXIT_FAILURE);
    }

    for(size_t i = 0; i < tests_to_run.size(); i++){
        UnitTest * test = tests_to_run[i];

        if (verbose)
            std::cout << test->name << " : " << std::flush;

        try {
            test->run();
            if (verbose)
                std::cout << "[PASS] " << std::endl;
            else
                std::cout << ".";
        }
        catch (thrusttest::UnitTestFailure& f){
            any_failed = true;
            if (verbose)
                std::cout << "[FAILURE] " << std::endl;
            else
                std::cout << "F";
            test_failures.push_back(std::make_pair(test,f));
        }
        catch (thrusttest::UnitTestKnownFailure& f){
            if (verbose)
                std::cout << "[KNOWN FAILURE] " << std::endl;
            else
                std::cout << "K";
            test_known_failures.push_back(std::make_pair(test,f));
        }
        catch (thrusttest::UnitTestError& e){
            any_failed = true;
            if (verbose)
                std::cout << "[ERROR] " << std::endl;
            else
                std::cout << "E";
            test_errors.push_back(std::make_pair(test,e));
        }
        catch (...){
            any_failed = true;
            if (verbose)
                std::cout << "[UNKNOWN EXCEPTION] " << std::endl;
            else
                std::cout << "U";
            test_exceptions.push_back(test);
        }

        error = cudaGetLastError();
        if(error){
            std::cerr << "\t[ERROR] CUDA Error detected after running " << test->name << ": [";
            std::cerr << std::string(cudaGetErrorString(error));
            std::cerr << "]" << std::endl;
            exit(EXIT_FAILURE);
        }

        std::cout.flush();
    }
    std::cout << std::endl;

    std::string hline = "================================================================";

    for(size_t i = 0; i < test_failures.size(); i++){
        std::cout << hline << std::endl;
        std::cout << "FAILURE: " << test_failures[i].first->name << std::endl;
        std::cout << test_failures[i].second << std::endl;
    }
    for(size_t i = 0; i < test_known_failures.size(); i++){
        std::cout << hline << std::endl;
        std::cout << "KNOWN FAILURE: " << test_known_failures[i].first->name << std::endl;
        std::cout << test_known_failures[i].second << std::endl;
    }
    for(size_t i = 0; i < test_errors.size(); i++){
        std::cout << hline << std::endl;
        std::cout << "ERROR: " << test_errors[i].first->name << std::endl;
        std::cout << test_errors[i].second << std::endl;
    }
    for(size_t i = 0; i < test_exceptions.size(); i++){
        std::cout << hline << std::endl;
        std::cout << "UNKNOWN EXCEPTION: " << test_exceptions[i]->name << std::endl;
    }

    std::cout << hline << std::endl;

    std::cout << "Totals: ";
    std::cout << test_failures.size() << " failures, ";
    std::cout << test_known_failures.size() << " known failures, ";
    std::cout << test_errors.size() << " errors and ";
    std::cout << test_exceptions.size() << " unknown exceptions." << std::endl;

    return any_failed;
}

bool UnitTestDriver::run_all_tests(const bool verbose)
{
  return run_tests(_test_list, verbose);
}

bool
UnitTestDriver::run_tests(const std::vector<std::string> &tests, const bool verbose)
{
  int i, j;
  std::vector<UnitTest *> tests_to_run;

  for (j=0; j < tests.size(); j++) {

    bool found = false;
    for (i = 0; !found && i < _test_list.size(); i++)
      if (tests[j] == _test_list[i]->name) {

        tests_to_run.push_back(_test_list[i]);
        found = true;
      }

    if (!found) {
      printf("[WARNING] UnitTestDriver::run_tests - test %s not found\n", tests[j].c_str());
    }
  }

  return run_tests(tests_to_run, verbose);
}

UnitTestDriver &
UnitTestDriver::s_driver()
{
  static UnitTestDriver s_instance;
  return s_instance;
}

<commit_msg>unit test driver now sorts tests by name for deterministic ordering<commit_after>#include "thrusttest/testframework.h"
#include "thrusttest/exceptions.h"

#include <cuda_runtime.h>
#include <iostream>
#include <cstdlib>
#include <algorithm>

void UnitTestDriver::register_test(UnitTest *test)
{
    UnitTestDriver::s_driver()._test_list.push_back(test);
}

UnitTest::UnitTest(const char * _name) : name(_name)
{
  UnitTestDriver::s_driver().register_test(this);
}

bool UnitTestDriver::run_tests(const std::vector<UnitTest *> &tests_to_run, const bool verbose)
{
    bool any_failed = false;

    std::cout << "Running " << tests_to_run.size() << " unit tests." << std::endl;

    std::vector< std::pair<UnitTest *,thrusttest::UnitTestFailure> >      test_failures;
    std::vector< std::pair<UnitTest *,thrusttest::UnitTestKnownFailure> > test_known_failures;
    std::vector< std::pair<UnitTest *,thrusttest::UnitTestError>   >      test_errors;
    std::vector< UnitTest * >                                             test_exceptions;

    cudaError_t error = cudaGetLastError();
    if(error){
        std::cerr << "[ERROR] CUDA Error detected before running tests: [";
        std::cerr << std::string(cudaGetErrorString(error));
        std::cerr << "]" << std::endl;
        exit(EXIT_FAILURE);
    }

    for(size_t i = 0; i < tests_to_run.size(); i++){
        UnitTest * test = tests_to_run[i];

        if (verbose)
            std::cout << test->name << " : " << std::flush;

        try {
            test->run();
            if (verbose)
                std::cout << "[PASS] " << std::endl;
            else
                std::cout << ".";
        }
        catch (thrusttest::UnitTestFailure& f){
            any_failed = true;
            if (verbose)
                std::cout << "[FAILURE] " << std::endl;
            else
                std::cout << "F";
            test_failures.push_back(std::make_pair(test,f));
        }
        catch (thrusttest::UnitTestKnownFailure& f){
            if (verbose)
                std::cout << "[KNOWN FAILURE] " << std::endl;
            else
                std::cout << "K";
            test_known_failures.push_back(std::make_pair(test,f));
        }
        catch (thrusttest::UnitTestError& e){
            any_failed = true;
            if (verbose)
                std::cout << "[ERROR] " << std::endl;
            else
                std::cout << "E";
            test_errors.push_back(std::make_pair(test,e));
        }
        catch (...){
            any_failed = true;
            if (verbose)
                std::cout << "[UNKNOWN EXCEPTION] " << std::endl;
            else
                std::cout << "U";
            test_exceptions.push_back(test);
        }

        error = cudaGetLastError();
        if(error){
            std::cerr << "\t[ERROR] CUDA Error detected after running " << test->name << ": [";
            std::cerr << std::string(cudaGetErrorString(error));
            std::cerr << "]" << std::endl;
            exit(EXIT_FAILURE);
        }

        std::cout.flush();
    }
    std::cout << std::endl;

    std::string hline = "================================================================";

    for(size_t i = 0; i < test_failures.size(); i++){
        std::cout << hline << std::endl;
        std::cout << "FAILURE: " << test_failures[i].first->name << std::endl;
        std::cout << test_failures[i].second << std::endl;
    }
    for(size_t i = 0; i < test_known_failures.size(); i++){
        std::cout << hline << std::endl;
        std::cout << "KNOWN FAILURE: " << test_known_failures[i].first->name << std::endl;
        std::cout << test_known_failures[i].second << std::endl;
    }
    for(size_t i = 0; i < test_errors.size(); i++){
        std::cout << hline << std::endl;
        std::cout << "ERROR: " << test_errors[i].first->name << std::endl;
        std::cout << test_errors[i].second << std::endl;
    }
    for(size_t i = 0; i < test_exceptions.size(); i++){
        std::cout << hline << std::endl;
        std::cout << "UNKNOWN EXCEPTION: " << test_exceptions[i]->name << std::endl;
    }

    std::cout << hline << std::endl;

    std::cout << "Totals: ";
    std::cout << test_failures.size() << " failures, ";
    std::cout << test_known_failures.size() << " known failures, ";
    std::cout << test_errors.size() << " errors and ";
    std::cout << test_exceptions.size() << " unknown exceptions." << std::endl;

    return any_failed;
}

// for sorting UnitTests by name
struct UnitTest_name_cmp
{
    bool operator()(const UnitTest * a, const UnitTest * b) const {
        return a->name < b->name;
    }

};

bool UnitTestDriver::run_all_tests(const bool verbose)
{
  std::vector<UnitTest *> tests_to_run(_test_list);

  // sort tests by name for deterministic results
  std::sort(tests_to_run.begin(), tests_to_run.end(), UnitTest_name_cmp());

  return run_tests(tests_to_run, verbose);
}

bool
UnitTestDriver::run_tests(const std::vector<std::string> &tests, const bool verbose)
{
  int i, j;
  std::vector<UnitTest *> tests_to_run;

  for (j=0; j < tests.size(); j++) {

    bool found = false;
    for (i = 0; !found && i < _test_list.size(); i++)
      if (tests[j] == _test_list[i]->name) {

        tests_to_run.push_back(_test_list[i]);
        found = true;
      }

    if (!found) {
      printf("[WARNING] UnitTestDriver::run_tests - test %s not found\n", tests[j].c_str());
    }
  }

  return run_tests(tests_to_run, verbose);
}

UnitTestDriver &
UnitTestDriver::s_driver()
{
  static UnitTestDriver s_instance;
  return s_instance;
}

<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexVB.cxx
 ** Lexer for Visual Basic and VBScript.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static int classifyWordVB(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) {

	char s[100];
	bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.') ||
		(styler[start] == '&' && tolower(styler[start+1]) == 'h');
	unsigned int i;
	for (i = 0; i < end - start + 1 && i < 30; i++) {
		s[i] = static_cast<char>(tolower(styler[start + i]));
	}
	s[i] = '\0';
	char chAttr = SCE_C_DEFAULT;
	if (wordIsNumber)
		chAttr = SCE_C_NUMBER;
	else {
		if (strcmp(s, "rem") == 0)
			chAttr = SCE_C_COMMENTLINE;
		else if (keywords.InList(s))
			chAttr = SCE_C_WORD;
	}
	styler.ColourTo(end, chAttr);
	if (chAttr == SCE_C_COMMENTLINE)
		return SCE_C_COMMENTLINE;
	else
		return SCE_C_DEFAULT;
}

static void ColouriseVBDoc(unsigned int startPos, int length, int initStyle,
                           WordList *keywordlists[], Accessor &styler) {

	WordList &keywords = *keywordlists[0];

	styler.StartAt(startPos);

	int visibleChars = 0;
	int state = initStyle;
	char chNext = styler[startPos];
	styler.StartSegment(startPos);
	int lengthDoc = startPos + length;
	for (int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if (styler.IsLeadByte(ch)) {
			chNext = styler.SafeGetCharAt(i + 2);
			i += 1;
			continue;
		}

		if (ch == '\r' || ch == '\n') {
			// End of line
			if (state == SCE_C_COMMENTLINE || state == SCE_C_PREPROCESSOR) {
				styler.ColourTo(i - 1, state);
				state = SCE_C_DEFAULT;
			}
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;

		if (state == SCE_C_DEFAULT) {
			if (iswordstart(ch)) {
				styler.ColourTo(i - 1, state);
				state = SCE_C_WORD;
			} else if (ch == '\'') {
				styler.ColourTo(i - 1, state);
				state = SCE_C_COMMENTLINE;
			} else if (ch == '\"') {
				styler.ColourTo(i - 1, state);
				state = SCE_C_STRING;
			} else if (ch == '#' && visibleChars == 1) {
				// Preprocessor commands are alone on their line
				styler.ColourTo(i - 1, state);
				state = SCE_C_PREPROCESSOR;
			} else if (ch == '&' && tolower(chNext) == 'h') {
				styler.ColourTo(i - 1, state);
				state = SCE_C_WORD;
			} else if (isoperator(ch)) {
				styler.ColourTo(i - 1, state);
				styler.ColourTo(i, SCE_C_OPERATOR);
			}
		} else if (state == SCE_C_WORD) {
			if (!iswordchar(ch)) {
				state = classifyWordVB(styler.GetStartSegment(), i - 1, keywords, styler);
				if (state == SCE_C_DEFAULT) {
					if (ch == '\'') {
						state = SCE_C_COMMENTLINE;
					} else if (ch == '\"') {
						state = SCE_C_STRING;
					} else if (isoperator(ch)) {
						styler.ColourTo(i - 1, state);
						styler.ColourTo(i, SCE_C_OPERATOR);
					}
				}
			}
		} else {
			if (state == SCE_C_STRING) {
				// VB doubles quotes to preserve them
				if (ch == '\"') {
					styler.ColourTo(i, state);
					state = SCE_C_DEFAULT;
					i++;
					ch = chNext;
					chNext = styler.SafeGetCharAt(i + 1);
				}
			}
			if (state == SCE_C_DEFAULT) {    // One of the above succeeded
				if (ch == '\'') {
					state = SCE_C_COMMENTLINE;
				} else if (ch == '\"') {
					state = SCE_C_STRING;
				} else if (iswordstart(ch)) {
					state = SCE_C_WORD;
				}
			}
		}
	}
	styler.ColourTo(lengthDoc, state);
}

LexerModule lmVB(SCLEX_VB, ColouriseVBDoc, "vb");
<commit_msg>Folding added by Willy Devaux.<commit_after>// Scintilla source code edit control
/** @file LexVB.cxx
 ** Lexer for Visual Basic and VBScript.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static int classifyWordVB(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) {

	char s[100];
	bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.') ||
		(styler[start] == '&' && tolower(styler[start+1]) == 'h');
	unsigned int i;
	for (i = 0; i < end - start + 1 && i < 30; i++) {
		s[i] = static_cast<char>(tolower(styler[start + i]));
	}
	s[i] = '\0';
	char chAttr = SCE_C_DEFAULT;
	if (wordIsNumber)
		chAttr = SCE_C_NUMBER;
	else {
		if (strcmp(s, "rem") == 0)
			chAttr = SCE_C_COMMENTLINE;
		else if (keywords.InList(s))
			chAttr = SCE_C_WORD;
	}
	styler.ColourTo(end, chAttr);
	if (chAttr == SCE_C_COMMENTLINE)
		return SCE_C_COMMENTLINE;
	else
		return SCE_C_DEFAULT;
}

static bool IsVBComment(Accessor &styler, int pos, int len) {
	return len>0 && styler[pos]=='\'';
}

static void ColouriseVBDoc(unsigned int startPos, int length, int initStyle,
                           WordList *keywordlists[], Accessor &styler) {

	WordList &keywords = *keywordlists[0];

	styler.StartAt(startPos);

	int visibleChars = 0;
	int state = initStyle;
	char chNext = styler[startPos];
	styler.StartSegment(startPos);
	int lengthDoc = startPos + length;
	for (int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if (styler.IsLeadByte(ch)) {
			chNext = styler.SafeGetCharAt(i + 2);
			i += 1;
			continue;
		}

		if (ch == '\r' || ch == '\n') {
			// End of line
			if (state == SCE_C_COMMENTLINE || state == SCE_C_PREPROCESSOR) {
				styler.ColourTo(i - 1, state);
				state = SCE_C_DEFAULT;
			}
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;

		if (state == SCE_C_DEFAULT) {
			if (iswordstart(ch)) {
				styler.ColourTo(i - 1, state);
				state = SCE_C_WORD;
			} else if (ch == '\'') {
				styler.ColourTo(i - 1, state);
				state = SCE_C_COMMENTLINE;
			} else if (ch == '\"') {
				styler.ColourTo(i - 1, state);
				state = SCE_C_STRING;
			} else if (ch == '#' && visibleChars == 1) {
				// Preprocessor commands are alone on their line
				styler.ColourTo(i - 1, state);
				state = SCE_C_PREPROCESSOR;
			} else if (ch == '&' && tolower(chNext) == 'h') {
				styler.ColourTo(i - 1, state);
				state = SCE_C_WORD;
			} else if (isoperator(ch)) {
				styler.ColourTo(i - 1, state);
				styler.ColourTo(i, SCE_C_OPERATOR);
			}
		} else if (state == SCE_C_WORD) {
			if (!iswordchar(ch)) {
				state = classifyWordVB(styler.GetStartSegment(), i - 1, keywords, styler);
				if (state == SCE_C_DEFAULT) {
					if (ch == '\'') {
						state = SCE_C_COMMENTLINE;
					} else if (ch == '\"') {
						state = SCE_C_STRING;
					} else if (isoperator(ch)) {
						styler.ColourTo(i - 1, state);
						styler.ColourTo(i, SCE_C_OPERATOR);
					}
				}
			}
		} else {
			if (state == SCE_C_STRING) {
				// VB doubles quotes to preserve them
				if (ch == '\"') {
					styler.ColourTo(i, state);
					state = SCE_C_DEFAULT;
					i++;
					ch = chNext;
					chNext = styler.SafeGetCharAt(i + 1);
				}
			}
			if (state == SCE_C_DEFAULT) {    // One of the above succeeded
				if (ch == '\'') {
					state = SCE_C_COMMENTLINE;
				} else if (ch == '\"') {
					state = SCE_C_STRING;
				} else if (iswordstart(ch)) {
					state = SCE_C_WORD;
				}
			}
		}
	}
	styler.ColourTo(lengthDoc, state);
}

static void FoldVBDoc(unsigned int startPos, int length, int initStyle,
						   WordList *[], Accessor &styler) {
	int lengthDoc = startPos + length;

	// Backtrack to previous line in case need to fix its fold status
	int lineCurrent = styler.GetLine(startPos);
	if (startPos > 0) {
		if (lineCurrent > 0) {
			lineCurrent--;
			startPos = styler.LineStart(lineCurrent);
			if (startPos == 0)
				initStyle = SCE_P_DEFAULT;
			else
				initStyle = styler.StyleAt(startPos-1);
		}
	}
	int state = initStyle & 31;
	int spaceFlags = 0;
	int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsVBComment);
	if ((state == SCE_P_TRIPLE) || (state == SCE_P_TRIPLEDOUBLE))
		indentCurrent |= SC_FOLDLEVELWHITEFLAG;
	char chNext = styler[startPos];
	for (int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styler.StyleAt(i) & 31;

		if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) {
			int lev = indentCurrent;
			int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsVBComment);
			if ((style == SCE_P_TRIPLE) || (style== SCE_P_TRIPLEDOUBLE))
				indentNext |= SC_FOLDLEVELWHITEFLAG;
			if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
				// Only non whitespace lines can be headers
				if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
					lev |= SC_FOLDLEVELHEADERFLAG;
				} else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
					// Line after is blank so check the next - maybe should continue further?
					int spaceFlags2 = 0;
					int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsVBComment);
					if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
						lev |= SC_FOLDLEVELHEADERFLAG;
					}
				}
			}
			indentCurrent = indentNext;
			styler.SetLevel(lineCurrent, lev);
			lineCurrent++;
		}
	}
}

LexerModule lmVB(SCLEX_VB, ColouriseVBDoc, "vb", FoldVBDoc);
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////
//
// The MIT License (MIT)
//
// Copyright (c) 2014 stevehalliwell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
////////////////////////////////////////////////////////////

#include <ResourceManager/ResourceFactory.hpp>
#include <ResourceManager/ResourceCreator.hpp>

namespace rm
{
    ////////////////////////////////////////////////////////////
    /// Initialise member variables
    ////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////
    /// Function definitions
    ////////////////////////////////////////////////////////////

    BaseResource::ResourceFactory()
    {

    }

    BaseResource::~ResourceFactory()
    {

    }

} //rm
<commit_msg>Added Functions to ResourceMananger.cpp<commit_after>////////////////////////////////////////////////////////////
//
// The MIT License (MIT)
//
// Copyright (c) 2014 stevehalliwell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
////////////////////////////////////////////////////////////

#include <ResourceManager/ResourceFactory.hpp>
#include <ResourceManager/ResourceCreator.hpp>

namespace rm
{
    ////////////////////////////////////////////////////////////
    /// Initialise member variables
    ////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////
    /// Function definitions
    ////////////////////////////////////////////////////////////

    BaseResource::ResourceFactory()
    {
    }

    BaseResource::~ResourceFactory()
    {
    }

    static std::shared_ptr<BaseResource> createResource(const std::string& path, const std::string& type)
    {
        throw("Not implemented");
    }

    static void addType()
    {

    }

} //rm
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <x0/http/HttpServer.h>
#include <x0/http/HttpClient.h>
#include <x0/Buffer.h>
#include <iostream>
#include <fstream>
#include <ev++.h>

using namespace x0;

class HttpServerTest : public ::testing::Test
{
public:
	HttpServerTest();

	void SetUp();
	void TearDown();

	void DirectoryTraversal();

private:
	struct ev::loop_ref loop_;
	HttpServer* http_;
};

HttpServerTest::HttpServerTest() :
	loop_(ev::default_loop()),
	http_(nullptr)
{
	FlowRunner::initialize();
}

void HttpServerTest::SetUp()
{
	http_ = new HttpServer(loop_);
}

void HttpServerTest::TearDown()
{
	delete http_;
	http_ = nullptr;
}

void HttpServerTest::request(const std::string& method, const std::string& path,
	const std::initializer_list<std::pair<std::string, std::string>>& headers, const Buffer& content,
	ResponseHandler callback)
{
	std::unordered_map<std::string, std::string> headerMap;
	for (auto item: headers)
		headerMap[item.first] = item.second;

	HttpClient::request(host_, port_, method, path, headerMap, content, callback);
}

TEST_F(HttpServerTest, Get)
{
	HttpClient::HeaderMap headers;
	Buffer body;

	HttpClient::request(IPAddress("127.0.0.1"), 8080, "GET", "/", {{"Foo", "bar"}, {"User-Agent", "HttpClient/1.0"}}, body,
	[&](HttpClientError ec, int status, const HttpClient::HeaderMap& headers, const BufferRef& content) {
		ASSERT_EQ(200, status);
		ASSERT_EQ(0, content.size());
	});
}

TEST_F(HttpServerTest, DirectoryTraversal)
{
	// TODO
}
<commit_msg>[tests] fixed compile issues<commit_after>#include <gtest/gtest.h>
#include <x0/http/HttpServer.h>
#include <x0/http/HttpClient.h>
#include <x0/Buffer.h>
#include <iostream>
#include <fstream>
#include <ev++.h>

using namespace x0;

class HttpServerTest : public ::testing::Test
{
public:
	HttpServerTest();

	void SetUp();
	void TearDown();

	void DirectoryTraversal();

	void request(const std::string& method, const std::string& path,
		const std::initializer_list<std::pair<std::string, std::string>>& headers, const Buffer& content,
		HttpClient::ResponseHandler callback);

private:
	struct ev::loop_ref loop_;
	IPAddress host_;
	int port_;
	HttpServer* http_;
};

HttpServerTest::HttpServerTest() :
	loop_(ev::default_loop()),
	host_("127.0.0.1"),
	port_(8080),
	http_(nullptr)
{
	FlowRunner::initialize();
}

void HttpServerTest::SetUp()
{
	http_ = new HttpServer(loop_);
}

void HttpServerTest::TearDown()
{
	delete http_;
	http_ = nullptr;
}

void HttpServerTest::request(const std::string& method, const std::string& path,
	const std::initializer_list<std::pair<std::string, std::string>>& headers, const Buffer& content,
	HttpClient::ResponseHandler callback)
{
	std::unordered_map<std::string, std::string> headerMap;
	for (auto item: headers)
		headerMap[item.first] = item.second;

	HttpClient::request(host_, port_, method, path, headerMap, content, callback);
}

TEST_F(HttpServerTest, Get)
{
	HttpClient::HeaderMap headers;
	Buffer body;

	HttpClient::request(IPAddress("127.0.0.1"), 8080, "GET", "/", {{"Foo", "bar"}, {"User-Agent", "HttpClient/1.0"}}, body,
	[&](HttpClientError ec, int status, const HttpClient::HeaderMap& headers, const BufferRef& content) {
		ASSERT_EQ(200, status);
		ASSERT_EQ(0, content.size());
	});
}

TEST_F(HttpServerTest, DirectoryTraversal)
{
	// TODO
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/transactionrecord.h>

#include <consensus/consensus.h>
#include <interfaces/wallet.h>
#include <key_io.h>
#include <policy/policy.h>
#include <timedata.h>
#include <validation.h>

#include <stdint.h>

/* Return positive answer if transaction should be shown in list.
 */
bool TransactionRecord::showTransaction()
{
    // There are currently no cases where we hide transactions, but
    // we may want to use this in the future for things like RBF.
    return true;
}

/*
 * Decompose CWallet transaction to model transaction records.
 */
QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interfaces::WalletTx& wtx)
{
    QList<TransactionRecord> parts;
    int64_t nTime = wtx.time;
    CAmount nCredit = valueFor(wtx.credit, ::policyAsset);
    CAmount nDebit = valueFor(wtx.debit, ::policyAsset);
    CAmount nNet = nCredit - nDebit;
    uint256 hash = wtx.tx->GetHash();
    std::map<std::string, std::string> mapValue = wtx.value_map;

    if (nNet > 0 || wtx.is_coinbase)
    {
        //
        // Credit
        //
        for(unsigned int i = 0; i < wtx.tx->vout.size(); i++)
        {
            isminetype mine = wtx.txout_is_mine[i];
            if(mine)
            {
                TransactionRecord sub(hash, nTime);
                CTxDestination address;
                sub.idx = i; // vout index
                sub.amount = wtx.txout_amounts[i];
                sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
                if (wtx.txout_address_is_mine[i])
                {
                    // Received by Bitcoin Address
                    sub.type = TransactionRecord::RecvWithAddress;
                    sub.address = EncodeDestination(wtx.txout_address[i]);
                    sub.asset = wtx.txout_assets[i];
                }
                else
                {
                    // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
                    sub.type = TransactionRecord::RecvFromOther;
                    sub.address = mapValue["from"];
                    sub.asset = wtx.txout_assets[i];
                }
                if (wtx.is_coinbase)
                {
                    // Generated
                    sub.type = TransactionRecord::Generated;
                    sub.asset = wtx.txout_assets[i];
                }

                parts.append(sub);
            }
        }
    }
    else
    {
        bool involvesWatchAddress = false;
        isminetype fAllFromMe = ISMINE_SPENDABLE;
        for (const isminetype mine : wtx.txin_is_mine)
        {
            if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
            if(fAllFromMe > mine) fAllFromMe = mine;
        }

        isminetype fAllToMe = ISMINE_SPENDABLE;
        for (unsigned int i = 0; i < wtx.txout_is_mine.size(); ++i) {
            const isminetype mine = wtx.txout_is_mine[i];
            const CTxOut txout = wtx.tx->vout[i];
            if (txout.IsFee()) {
                // explicit fee; ignore
                continue;
            }
            if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
            if(fAllToMe > mine) fAllToMe = mine;
        }

        if (fAllFromMe && fAllToMe)
        {
            // Payment to self
            CAmount nChange = valueFor(wtx.change, ::policyAsset);

            parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
                            -(nDebit - nChange) + (nCredit - nChange), ::policyAsset));
            parts.last().involvesWatchAddress = involvesWatchAddress;   // maybe pass to TransactionRecord as constructor argument
        }
        else if (fAllFromMe)
        {
            //
            // Debit
            //

            for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++)
            {
                const CTxOut& txout = wtx.tx->vout[nOut];

                if(wtx.txout_is_mine[nOut] || txout.IsFee())
                {
                    // Ignore parts sent to self, as this is usually the change
                    // from a transaction sent back to our own address.
                    continue;
                }

                TransactionRecord sub(hash, nTime);
                sub.idx = nOut;
                sub.involvesWatchAddress = involvesWatchAddress;
                sub.amount = -wtx.txout_amounts[nOut];
                sub.asset = wtx.txout_assets[nOut];

                if (!boost::get<CNoDestination>(&wtx.txout_address[nOut]))
                {
                    // Sent to Bitcoin Address
                    sub.type = TransactionRecord::SendToAddress;
                    sub.address = EncodeDestination(wtx.txout_address[nOut]);
                }
                else
                {
                    // Sent to IP, or other non-address transaction like OP_EVAL
                    sub.type = TransactionRecord::SendToOther;
                    sub.address = mapValue["to"];
                }
                parts.append(sub);
            }
            CAmount nTxFee = GetFeeMap(*wtx.tx)[::policyAsset];
            if (nTxFee > 0)
            {
                TransactionRecord sub(hash, nTime);
                sub.type = TransactionRecord::Fee;
                sub.amount = -nTxFee;
                sub.asset = ::policyAsset;
                parts.append(sub);
            }
        }
        else
        {
            //
            // Mixed debit transaction, can't break down payees
            //
            parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, CAsset()));
            parts.last().involvesWatchAddress = involvesWatchAddress;
        }
    }

    return parts;
}

void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int64_t adjustedTime)
{
    // Determine transaction status

    // Sort order, unrecorded transactions sort to the top
    status.sortKey = strprintf("%010d-%01d-%010u-%03d",
        wtx.block_height,
        wtx.is_coinbase ? 1 : 0,
        wtx.time_received,
        idx);
    status.countsForBalance = wtx.is_trusted && !(wtx.blocks_to_maturity > 0);
    status.depth = wtx.depth_in_main_chain;
    status.cur_num_blocks = numBlocks;

    if (!wtx.is_final)
    {
        if (wtx.lock_time < LOCKTIME_THRESHOLD)
        {
            status.status = TransactionStatus::OpenUntilBlock;
            status.open_for = wtx.lock_time - numBlocks;
        }
        else
        {
            status.status = TransactionStatus::OpenUntilDate;
            status.open_for = wtx.lock_time;
        }
    }
    // For generated transactions, determine maturity
    else if(type == TransactionRecord::Generated)
    {
        if (wtx.blocks_to_maturity > 0)
        {
            status.status = TransactionStatus::Immature;

            if (wtx.is_in_main_chain)
            {
                status.matures_in = wtx.blocks_to_maturity;
            }
            else
            {
                status.status = TransactionStatus::NotAccepted;
            }
        }
        else
        {
            status.status = TransactionStatus::Confirmed;
        }
    }
    else
    {
        if (status.depth < 0)
        {
            status.status = TransactionStatus::Conflicted;
        }
        else if (status.depth == 0)
        {
            status.status = TransactionStatus::Unconfirmed;
            if (wtx.is_abandoned)
                status.status = TransactionStatus::Abandoned;
        }
        else if (status.depth < RecommendedNumConfirmations)
        {
            status.status = TransactionStatus::Confirming;
        }
        else
        {
            status.status = TransactionStatus::Confirmed;
        }
    }
    status.needsUpdate = false;
}

bool TransactionRecord::statusUpdateNeeded(int numBlocks) const
{
    return status.cur_num_blocks != numBlocks || status.needsUpdate;
}

QString TransactionRecord::getTxHash() const
{
    return QString::fromStdString(hash.ToString());
}

int TransactionRecord::getOutputIndex() const
{
    return idx;
}
<commit_msg>GUI: TransactionRecord: Turn non-bitcoin fees into entries<commit_after>// Copyright (c) 2011-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/transactionrecord.h>

#include <consensus/consensus.h>
#include <interfaces/wallet.h>
#include <key_io.h>
#include <policy/policy.h>
#include <timedata.h>
#include <validation.h>

#include <stdint.h>

/* Return positive answer if transaction should be shown in list.
 */
bool TransactionRecord::showTransaction()
{
    // There are currently no cases where we hide transactions, but
    // we may want to use this in the future for things like RBF.
    return true;
}

/*
 * Decompose CWallet transaction to model transaction records.
 */
QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interfaces::WalletTx& wtx)
{
    QList<TransactionRecord> parts;
    int64_t nTime = wtx.time;
    CAmount nCredit = valueFor(wtx.credit, ::policyAsset);
    CAmount nDebit = valueFor(wtx.debit, ::policyAsset);
    CAmount nNet = nCredit - nDebit;
    uint256 hash = wtx.tx->GetHash();
    std::map<std::string, std::string> mapValue = wtx.value_map;

    if (nNet > 0 || wtx.is_coinbase)
    {
        //
        // Credit
        //
        for(unsigned int i = 0; i < wtx.tx->vout.size(); i++)
        {
            isminetype mine = wtx.txout_is_mine[i];
            if(mine)
            {
                TransactionRecord sub(hash, nTime);
                CTxDestination address;
                sub.idx = i; // vout index
                sub.amount = wtx.txout_amounts[i];
                sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
                if (wtx.txout_address_is_mine[i])
                {
                    // Received by Bitcoin Address
                    sub.type = TransactionRecord::RecvWithAddress;
                    sub.address = EncodeDestination(wtx.txout_address[i]);
                    sub.asset = wtx.txout_assets[i];
                }
                else
                {
                    // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
                    sub.type = TransactionRecord::RecvFromOther;
                    sub.address = mapValue["from"];
                    sub.asset = wtx.txout_assets[i];
                }
                if (wtx.is_coinbase)
                {
                    // Generated
                    sub.type = TransactionRecord::Generated;
                    sub.asset = wtx.txout_assets[i];
                }

                parts.append(sub);
            }
        }
    }
    else
    {
        bool involvesWatchAddress = false;
        isminetype fAllFromMe = ISMINE_SPENDABLE;
        for (const isminetype mine : wtx.txin_is_mine)
        {
            if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
            if(fAllFromMe > mine) fAllFromMe = mine;
        }

        isminetype fAllToMe = ISMINE_SPENDABLE;
        for (unsigned int i = 0; i < wtx.txout_is_mine.size(); ++i) {
            const isminetype mine = wtx.txout_is_mine[i];
            const CTxOut txout = wtx.tx->vout[i];
            if (txout.IsFee()) {
                // explicit fee; ignore
                continue;
            }
            if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
            if(fAllToMe > mine) fAllToMe = mine;
        }

        if (fAllFromMe && fAllToMe)
        {
            // Payment to self
            CAmount nChange = valueFor(wtx.change, ::policyAsset);

            parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
                            -(nDebit - nChange) + (nCredit - nChange), ::policyAsset));
            parts.last().involvesWatchAddress = involvesWatchAddress;   // maybe pass to TransactionRecord as constructor argument
        }
        else if (fAllFromMe)
        {
            //
            // Debit
            //

            for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++)
            {
                const CTxOut& txout = wtx.tx->vout[nOut];

                if(wtx.txout_is_mine[nOut] || txout.IsFee())
                {
                    // Ignore parts sent to self, as this is usually the change
                    // from a transaction sent back to our own address.
                    continue;
                }

                TransactionRecord sub(hash, nTime);
                sub.idx = nOut;
                sub.involvesWatchAddress = involvesWatchAddress;
                sub.amount = -wtx.txout_amounts[nOut];
                sub.asset = wtx.txout_assets[nOut];

                if (!boost::get<CNoDestination>(&wtx.txout_address[nOut]))
                {
                    // Sent to Bitcoin Address
                    sub.type = TransactionRecord::SendToAddress;
                    sub.address = EncodeDestination(wtx.txout_address[nOut]);
                }
                else
                {
                    // Sent to IP, or other non-address transaction like OP_EVAL
                    sub.type = TransactionRecord::SendToOther;
                    sub.address = mapValue["to"];
                }
                parts.append(sub);
            }

            for (const auto& tx_fee : GetFeeMap(*wtx.tx)) {
                if (!tx_fee.second) continue;
                TransactionRecord sub(hash, nTime);
                sub.type = TransactionRecord::Fee;
                sub.asset = tx_fee.first;
                sub.amount = -tx_fee.second;
                parts.append(sub);
            }
        }
        else
        {
            //
            // Mixed debit transaction, can't break down payees
            //
            parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, CAsset()));
            parts.last().involvesWatchAddress = involvesWatchAddress;
        }
    }

    return parts;
}

void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int64_t adjustedTime)
{
    // Determine transaction status

    // Sort order, unrecorded transactions sort to the top
    status.sortKey = strprintf("%010d-%01d-%010u-%03d",
        wtx.block_height,
        wtx.is_coinbase ? 1 : 0,
        wtx.time_received,
        idx);
    status.countsForBalance = wtx.is_trusted && !(wtx.blocks_to_maturity > 0);
    status.depth = wtx.depth_in_main_chain;
    status.cur_num_blocks = numBlocks;

    if (!wtx.is_final)
    {
        if (wtx.lock_time < LOCKTIME_THRESHOLD)
        {
            status.status = TransactionStatus::OpenUntilBlock;
            status.open_for = wtx.lock_time - numBlocks;
        }
        else
        {
            status.status = TransactionStatus::OpenUntilDate;
            status.open_for = wtx.lock_time;
        }
    }
    // For generated transactions, determine maturity
    else if(type == TransactionRecord::Generated)
    {
        if (wtx.blocks_to_maturity > 0)
        {
            status.status = TransactionStatus::Immature;

            if (wtx.is_in_main_chain)
            {
                status.matures_in = wtx.blocks_to_maturity;
            }
            else
            {
                status.status = TransactionStatus::NotAccepted;
            }
        }
        else
        {
            status.status = TransactionStatus::Confirmed;
        }
    }
    else
    {
        if (status.depth < 0)
        {
            status.status = TransactionStatus::Conflicted;
        }
        else if (status.depth == 0)
        {
            status.status = TransactionStatus::Unconfirmed;
            if (wtx.is_abandoned)
                status.status = TransactionStatus::Abandoned;
        }
        else if (status.depth < RecommendedNumConfirmations)
        {
            status.status = TransactionStatus::Confirming;
        }
        else
        {
            status.status = TransactionStatus::Confirmed;
        }
    }
    status.needsUpdate = false;
}

bool TransactionRecord::statusUpdateNeeded(int numBlocks) const
{
    return status.cur_num_blocks != numBlocks || status.needsUpdate;
}

QString TransactionRecord::getTxHash() const
{
    return QString::fromStdString(hash.ToString());
}

int TransactionRecord::getOutputIndex() const
{
    return idx;
}
<|endoftext|>


<commit_before>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <memory>
#include <string>
#include <vector>
#include "gtest/gtest.h"

#ifdef __GNUC__
#include <cxxabi.h>
#include <execinfo.h>
#include <malloc.h>
#endif

#include "rclcpp/strategies/allocator_memory_strategy.hpp"
#include "rclcpp/rclcpp.hpp"

#include "std_msgs/msg/u_int32.hpp"
#include "tlsf_cpp/tlsf.hpp"

#ifdef RMW_IMPLEMENTATION
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
# define CLASSNAME(NAME, SUFFIX) CLASSNAME_(NAME, SUFFIX)
#else
# define CLASSNAME(NAME, SUFFIX) NAME
#endif

// TODO(jacquelinekay) improve this ignore rule (dogfooding or no allocations)
static const size_t num_rmw_tokens = 6;
static const char * rmw_tokens[num_rmw_tokens] = {
  "librmw", "dds", "DDS", "dcps", "DCPS", "fastrtps"
};

static const size_t iterations = 1;

static bool verbose = false;
static bool ignore_middleware_tokens = true;
static bool test_init = false;
static bool fail = false;

inline bool check_stacktrace(const char ** tokens, size_t num_tokens, size_t max_frames = 15);

/// Declare a function pointer into which we will store the default malloc.
static void * (* prev_malloc_hook)(size_t, const void *);

// Use pragma to ignore a warning for using __malloc_hook, which is deprecated (but still awesome).
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

static void * testing_malloc(size_t size, const void * caller)
{
  (void)caller;
  // Set the malloc implementation to the default malloc hook so that we can call it implicitly
  // to initialize a string, otherwise this function will loop infinitely.
  __malloc_hook = prev_malloc_hook;

  if (test_init) {
    fail |= !check_stacktrace(rmw_tokens, num_rmw_tokens);
  }

  // Execute the requested malloc.
  void * mem = std::malloc(size);
  // Set the malloc hook back to this function, so that we can intercept future mallocs.
  __malloc_hook = testing_malloc;
  return mem;
}

/// Function to be called when the malloc hook is initialized.
void init_malloc_hook()
{
  // Store the default malloc.
  prev_malloc_hook = __malloc_hook;
  // Set our custom malloc to the malloc hook.
  __malloc_hook = testing_malloc;
}
#pragma GCC diagnostic pop

/// Set the hook for malloc initialize so that init_malloc_hook gets called.
void(*volatile __malloc_initialize_hook)(void) = init_malloc_hook;

/** Check a demangled stack backtrace of the caller function for the given tokens.
 ** Adapted from: https://panthema.net/2008/0901-stacktrace-demangled
 **/
bool check_stacktrace(const char ** tokens, size_t num_tokens, size_t max_frames)
{
#ifdef __GNUC__
  bool match = false;

  // storage array for stack trace address data
  void * addrlist[max_frames + 1];

  // retrieve current stack addresses
  int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void *));

  if (addrlen == 0) {
    fprintf(stderr, "WARNING: stack trace empty, possibly corrupt\n");
    return false;
  }

  // resolve addresses into strings containing "filename(function+address)",
  // this array must be free()-ed
  char ** symbollist = backtrace_symbols(addrlist, addrlen);

  // initialize string string which will be filled with the demangled function name
  // allocate string which will be filled with the demangled function name
  size_t funcnamesize = 256;
  char * funcname = static_cast<char *>(std::malloc(funcnamesize));

  if (verbose) {
    fprintf(stderr, ">>>> stack trace:\n");
  }

  // iterate over the returned symbol lines. skip the first, it is the
  // address of this function.
  for (int i = 1; i < addrlen; i++) {
    char * begin_name = 0, * begin_offset = 0, * end_offset = 0;

    // find parentheses and +address offset surrounding the mangled name:
    // ./module(function+0x15c) [0x8048a6d]
    for (char * p = symbollist[i]; *p; ++p) {
      if (*p == '(') {
        begin_name = p;
      } else if (*p == '+') {
        begin_offset = p;
      } else if (*p == ')' && begin_offset) {
        end_offset = p;
        break;
      }
    }

    if (begin_name && begin_offset && end_offset &&
      begin_name < begin_offset)
    {
      *begin_name++ = '\0';
      *begin_offset++ = '\0';
      *end_offset = '\0';

      int status;
      char * ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
      if (status == 0) {
        funcname = ret;  // use possibly realloc()-ed string
        for (size_t j = 0; j < num_tokens; ++j) {
          if (strstr(symbollist[i],
            tokens[j]) != nullptr || strstr(funcname, tokens[j]) != nullptr)
          {
            match = true;
            break;
          }
        }
        if (verbose) {
          fprintf(stderr, "  %s : %s+%s\n", symbollist[i], funcname, begin_offset);
        }
      } else {
        // demangling failed. Output function name as a C function with
        // no arguments.
        for (size_t j = 0; j < num_tokens; j++) {
          if (strstr(symbollist[i],
            tokens[j]) != nullptr || strstr(begin_name, tokens[j]) != nullptr)
          {
            match = true;
            break;
          }
        }
        if (verbose) {
          fprintf(stderr, "  %s : %s()+%s\n", symbollist[i], begin_name, begin_offset);
        }
      }
    } else {
      // couldn't parse the line? print the whole line.
      for (size_t j = 0; j < num_tokens; j++) {
        if (strstr(symbollist[i], tokens[j]) != nullptr) {
          match = true;
          break;
        }
      }
      if (verbose) {
        fprintf(stderr, "  %s\n", symbollist[i]);
      }
    }
  }

  free(funcname);
  free(symbollist);
  if (!ignore_middleware_tokens) {
    return false;
  }
  return match;
#else
  return true;
#endif  // __GNUC__
}

void * operator new(std::size_t size)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  __malloc_hook = prev_malloc_hook;

  if (test_init) {
    // Check the stacktrace to see the call originated in librmw or a DDS implementation
    fail |= !check_stacktrace(rmw_tokens, num_rmw_tokens);
  }
  void * ptr = std::malloc(size);

  __malloc_hook = testing_malloc;
#pragma GCC diagnostic pop
  return ptr;
}

void operator delete(void * ptr) noexcept
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  __malloc_hook = prev_malloc_hook;

  if (ptr != nullptr) {
    if (test_init) {
      // Check the stacktrace to see the call originated in librmw or a DDS implementation
      fail |= !check_stacktrace(rmw_tokens, num_rmw_tokens);
    }

    std::free(ptr);
    ptr = nullptr;
  }
  __malloc_hook = testing_malloc;
#pragma GCC diagnostic pop
}

void operator delete(void * ptr, size_t) noexcept
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  __malloc_hook = prev_malloc_hook;

  if (ptr != nullptr) {
    if (test_init) {
      // Check the stacktrace to see the call originated in librmw or a DDS implementation
      fail |= !check_stacktrace(rmw_tokens, num_rmw_tokens);
    }

    std::free(ptr);
    ptr = nullptr;
  }
  __malloc_hook = testing_malloc;
#pragma GCC diagnostic pop
}

template<typename T = void>
using TLSFAllocator = tlsf_heap_allocator<T>;

using rclcpp::memory_strategies::allocator_memory_strategy::AllocatorMemoryStrategy;

class CLASSNAME (AllocatorTest, RMW_IMPLEMENTATION) : public::testing::Test
{
protected:
  std::string test_name_;

  rclcpp::node::Node::SharedPtr node_;
  rclcpp::executors::SingleThreadedExecutor::SharedPtr executor_;
  rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
  rclcpp::publisher::Publisher<std_msgs::msg::UInt32,
  TLSFAllocator<void>>::SharedPtr publisher_;
  rclcpp::message_memory_strategy::MessageMemoryStrategy<std_msgs::msg::UInt32,
  TLSFAllocator<void>>::SharedPtr msg_memory_strategy_;
  std::shared_ptr<TLSFAllocator<void>> alloc;

  bool intra_process_;

  using UInt32Allocator = TLSFAllocator<std_msgs::msg::UInt32>;
  using UInt32Deleter = rclcpp::allocator::Deleter<UInt32Allocator, std_msgs::msg::UInt32>;

  void initialize(bool intra_process, const std::string & name)
  {
    test_name_ = name;
    intra_process_ = intra_process;

    auto context = rclcpp::contexts::default_context::get_global_default_context();
    auto intra_process_manager_state =
      std::make_shared<rclcpp::intra_process_manager::IntraProcessManagerImpl<UInt32Allocator>>();
    context->get_sub_context<rclcpp::intra_process_manager::IntraProcessManager>(
      intra_process_manager_state);

    node_ = rclcpp::Node::make_shared(name, context, intra_process);
    alloc = std::make_shared<TLSFAllocator<void>>();
    msg_memory_strategy_ =
      std::make_shared<rclcpp::message_memory_strategy::MessageMemoryStrategy
      <std_msgs::msg::UInt32,
      TLSFAllocator<void>>>(alloc);
    publisher_ = node_->create_publisher<std_msgs::msg::UInt32>(name, 10, alloc);
    memory_strategy_ =
      std::make_shared<AllocatorMemoryStrategy<TLSFAllocator<void>>>(alloc);

    rclcpp::executor::ExecutorArgs args;
    args.memory_strategy = memory_strategy_;
    rclcpp::executors::SingleThreadedExecutor executor(args);
    executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>(args);

    executor_->add_node(node_);
  }

  CLASSNAME(AllocatorTest, RMW_IMPLEMENTATION)() {
  }

  ~CLASSNAME(AllocatorTest, RMW_IMPLEMENTATION)() {
  }
};

TEST_F(CLASSNAME(AllocatorTest, RMW_IMPLEMENTATION), allocator_shared_ptr) {
  initialize(false, "allocator_shared_ptr");
  size_t counter = 0;
  auto callback = [&counter](std_msgs::msg::UInt32::SharedPtr msg) -> void
    {
      EXPECT_EQ(counter, msg->data);
      counter++;
    };

  auto subscriber = node_->create_subscription<std_msgs::msg::UInt32>(
    "allocator_shared_ptr", 10, callback, nullptr, false, msg_memory_strategy_, alloc);
  // Create msg to be published
  auto msg = std::allocate_shared<std_msgs::msg::UInt32>(*alloc.get());

  rclcpp::utilities::sleep_for(std::chrono::milliseconds(1));
  // After test_initialization, global new should only be called from within TLSFAllocator.
  test_init = true;
  for (uint32_t i = 0; i < iterations; i++) {
    msg->data = i;
    publisher_->publish(msg);
    rclcpp::utilities::sleep_for(std::chrono::milliseconds(1));
    executor_->spin_some();
  }
  test_init = false;
  EXPECT_FALSE(fail);
  fail = false;
}

TEST_F(CLASSNAME(AllocatorTest, RMW_IMPLEMENTATION), allocator_unique_ptr) {
  initialize(true, "allocator_unique_ptr");
  size_t counter = 0;
  auto callback =
    [&counter](std_msgs::msg::UInt32::UniquePtrWithDeleter<UInt32Deleter> msg) -> void
    {
      EXPECT_EQ(counter, msg->data);
      counter++;
    };

  auto subscriber = node_->create_subscription<std_msgs::msg::UInt32>(
    "allocator_unique_ptr", 10, callback, nullptr, false, msg_memory_strategy_, alloc);

  TLSFAllocator<std_msgs::msg::UInt32> msg_alloc;

  rclcpp::utilities::sleep_for(std::chrono::milliseconds(1));
  // After test_initialization, global new should only be called from within TLSFAllocator.
  test_init = true;
  for (uint32_t i = 0; i < iterations; i++) {
    auto msg = std::unique_ptr<std_msgs::msg::UInt32, UInt32Deleter>(
      std::allocator_traits<UInt32Allocator>::allocate(msg_alloc, 1));
    msg->data = i;
    publisher_->publish(msg);
    rclcpp::utilities::sleep_for(std::chrono::milliseconds(1));
    executor_->spin_some();
  }
  test_init = false;
  EXPECT_FALSE(fail);
  fail = false;
}

void print_help()
{
  printf("--all-tokens: Do not ignore middleware tokens.\n");
  printf("--verbose: Report stack traces and allocation statistics.\n");
}

int main(int argc, char ** argv)
{
  rclcpp::init(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  // argc and argv are modified by InitGoogleTest
  std::vector<std::string> args(argv + 1, argv + argc);

  if (std::find(args.begin(), args.end(), "--help") != args.end()) {
    print_help();
    return 0;
  }
  verbose = std::find(args.begin(), args.end(), "--verbose") != args.end();
  ignore_middleware_tokens = std::find(args.begin(), args.end(), "--all-tokens") == args.end();

  return RUN_ALL_TESTS();
}
<commit_msg>fix style<commit_after>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <memory>
#include <string>
#include <vector>
#include "gtest/gtest.h"

#ifdef __GNUC__
#include <cxxabi.h>
#include <execinfo.h>
#include <malloc.h>
#endif

#include "rclcpp/strategies/allocator_memory_strategy.hpp"
#include "rclcpp/rclcpp.hpp"

#include "std_msgs/msg/u_int32.hpp"
#include "tlsf_cpp/tlsf.hpp"

#ifdef RMW_IMPLEMENTATION
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
# define CLASSNAME(NAME, SUFFIX) CLASSNAME_(NAME, SUFFIX)
#else
# define CLASSNAME(NAME, SUFFIX) NAME
#endif

// TODO(jacquelinekay) improve this ignore rule (dogfooding or no allocations)
static const size_t num_rmw_tokens = 6;
static const char * rmw_tokens[num_rmw_tokens] = {
  "librmw", "dds", "DDS", "dcps", "DCPS", "fastrtps"
};

static const size_t iterations = 1;

static bool verbose = false;
static bool ignore_middleware_tokens = true;
static bool test_init = false;
static bool fail = false;

inline bool check_stacktrace(const char ** tokens, size_t num_tokens, size_t max_frames = 15);

/// Declare a function pointer into which we will store the default malloc.
static void * (* prev_malloc_hook)(size_t, const void *);

// Use pragma to ignore a warning for using __malloc_hook, which is deprecated (but still awesome).
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

static void * testing_malloc(size_t size, const void * caller)
{
  (void)caller;
  // Set the malloc implementation to the default malloc hook so that we can call it implicitly
  // to initialize a string, otherwise this function will loop infinitely.
  __malloc_hook = prev_malloc_hook;

  if (test_init) {
    fail |= !check_stacktrace(rmw_tokens, num_rmw_tokens);
  }

  // Execute the requested malloc.
  void * mem = std::malloc(size);
  // Set the malloc hook back to this function, so that we can intercept future mallocs.
  __malloc_hook = testing_malloc;
  return mem;
}

/// Function to be called when the malloc hook is initialized.
void init_malloc_hook()
{
  // Store the default malloc.
  prev_malloc_hook = __malloc_hook;
  // Set our custom malloc to the malloc hook.
  __malloc_hook = testing_malloc;
}
#pragma GCC diagnostic pop

/// Set the hook for malloc initialize so that init_malloc_hook gets called.
void(*volatile __malloc_initialize_hook)(void) = init_malloc_hook;

/** Check a demangled stack backtrace of the caller function for the given tokens.
 ** Adapted from: https://panthema.net/2008/0901-stacktrace-demangled
 **/
bool check_stacktrace(const char ** tokens, size_t num_tokens, size_t max_frames)
{
#ifdef __GNUC__
  bool match = false;

  // storage array for stack trace address data
  void * addrlist[max_frames + 1];

  // retrieve current stack addresses
  int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void *));

  if (addrlen == 0) {
    fprintf(stderr, "WARNING: stack trace empty, possibly corrupt\n");
    return false;
  }

  // resolve addresses into strings containing "filename(function+address)",
  // this array must be free()-ed
  char ** symbollist = backtrace_symbols(addrlist, addrlen);

  // initialize string string which will be filled with the demangled function name
  // allocate string which will be filled with the demangled function name
  size_t funcnamesize = 256;
  char * funcname = static_cast<char *>(std::malloc(funcnamesize));

  if (verbose) {
    fprintf(stderr, ">>>> stack trace:\n");
  }

  // iterate over the returned symbol lines. skip the first, it is the
  // address of this function.
  for (int i = 1; i < addrlen; i++) {
    char * begin_name = 0, * begin_offset = 0, * end_offset = 0;

    // find parentheses and +address offset surrounding the mangled name:
    // ./module(function+0x15c) [0x8048a6d]
    for (char * p = symbollist[i]; *p; ++p) {
      if (*p == '(') {
        begin_name = p;
      } else if (*p == '+') {
        begin_offset = p;
      } else if (*p == ')' && begin_offset) {
        end_offset = p;
        break;
      }
    }

    if (begin_name && begin_offset && end_offset &&
      begin_name < begin_offset)
    {
      *begin_name++ = '\0';
      *begin_offset++ = '\0';
      *end_offset = '\0';

      int status;
      char * ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
      if (status == 0) {
        funcname = ret;  // use possibly realloc()-ed string
        for (size_t j = 0; j < num_tokens; ++j) {
          if (strstr(symbollist[i],
            tokens[j]) != nullptr || strstr(funcname, tokens[j]) != nullptr)
          {
            match = true;
            break;
          }
        }
        if (verbose) {
          fprintf(stderr, "  %s : %s+%s\n", symbollist[i], funcname, begin_offset);
        }
      } else {
        // demangling failed. Output function name as a C function with
        // no arguments.
        for (size_t j = 0; j < num_tokens; j++) {
          if (strstr(symbollist[i],
            tokens[j]) != nullptr || strstr(begin_name, tokens[j]) != nullptr)
          {
            match = true;
            break;
          }
        }
        if (verbose) {
          fprintf(stderr, "  %s : %s()+%s\n", symbollist[i], begin_name, begin_offset);
        }
      }
    } else {
      // couldn't parse the line? print the whole line.
      for (size_t j = 0; j < num_tokens; j++) {
        if (strstr(symbollist[i], tokens[j]) != nullptr) {
          match = true;
          break;
        }
      }
      if (verbose) {
        fprintf(stderr, "  %s\n", symbollist[i]);
      }
    }
  }

  free(funcname);
  free(symbollist);
  if (!ignore_middleware_tokens) {
    return false;
  }
  return match;
#else
  return true;
#endif  // __GNUC__
}

void * operator new(std::size_t size)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  __malloc_hook = prev_malloc_hook;

  if (test_init) {
    // Check the stacktrace to see the call originated in librmw or a DDS implementation
    fail |= !check_stacktrace(rmw_tokens, num_rmw_tokens);
  }
  void * ptr = std::malloc(size);

  __malloc_hook = testing_malloc;
#pragma GCC diagnostic pop
  return ptr;
}

void operator delete(void * ptr) noexcept
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  __malloc_hook = prev_malloc_hook;

  if (ptr != nullptr) {
    if (test_init) {
      // Check the stacktrace to see the call originated in librmw or a DDS implementation
      fail |= !check_stacktrace(rmw_tokens, num_rmw_tokens);
    }

    std::free(ptr);
    ptr = nullptr;
  }
  __malloc_hook = testing_malloc;
#pragma GCC diagnostic pop
}

void operator delete(void * ptr, size_t) noexcept
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  __malloc_hook = prev_malloc_hook;

  if (ptr != nullptr) {
    if (test_init) {
      // Check the stacktrace to see the call originated in librmw or a DDS implementation
      fail |= !check_stacktrace(rmw_tokens, num_rmw_tokens);
    }

    std::free(ptr);
    ptr = nullptr;
  }
  __malloc_hook = testing_malloc;
#pragma GCC diagnostic pop
}

template<typename T = void>
using TLSFAllocator = tlsf_heap_allocator<T>;

using rclcpp::memory_strategies::allocator_memory_strategy::AllocatorMemoryStrategy;

class CLASSNAME (AllocatorTest, RMW_IMPLEMENTATION) : public ::testing::Test
{
protected:
  std::string test_name_;

  rclcpp::node::Node::SharedPtr node_;
  rclcpp::executors::SingleThreadedExecutor::SharedPtr executor_;
  rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
  rclcpp::publisher::Publisher<std_msgs::msg::UInt32,
  TLSFAllocator<void>>::SharedPtr publisher_;
  rclcpp::message_memory_strategy::MessageMemoryStrategy<std_msgs::msg::UInt32,
  TLSFAllocator<void>>::SharedPtr msg_memory_strategy_;
  std::shared_ptr<TLSFAllocator<void>> alloc;

  bool intra_process_;

  using UInt32Allocator = TLSFAllocator<std_msgs::msg::UInt32>;
  using UInt32Deleter = rclcpp::allocator::Deleter<UInt32Allocator, std_msgs::msg::UInt32>;

  void initialize(bool intra_process, const std::string & name)
  {
    test_name_ = name;
    intra_process_ = intra_process;

    auto context = rclcpp::contexts::default_context::get_global_default_context();
    auto intra_process_manager_state =
      std::make_shared<rclcpp::intra_process_manager::IntraProcessManagerImpl<UInt32Allocator>>();
    context->get_sub_context<rclcpp::intra_process_manager::IntraProcessManager>(
      intra_process_manager_state);

    node_ = rclcpp::Node::make_shared(name, context, intra_process);
    alloc = std::make_shared<TLSFAllocator<void>>();
    msg_memory_strategy_ =
      std::make_shared<rclcpp::message_memory_strategy::MessageMemoryStrategy
      <std_msgs::msg::UInt32,
      TLSFAllocator<void>>>(alloc);
    publisher_ = node_->create_publisher<std_msgs::msg::UInt32>(name, 10, alloc);
    memory_strategy_ =
      std::make_shared<AllocatorMemoryStrategy<TLSFAllocator<void>>>(alloc);

    rclcpp::executor::ExecutorArgs args;
    args.memory_strategy = memory_strategy_;
    rclcpp::executors::SingleThreadedExecutor executor(args);
    executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>(args);

    executor_->add_node(node_);
  }

  CLASSNAME(AllocatorTest, RMW_IMPLEMENTATION)() {
  }

  ~CLASSNAME(AllocatorTest, RMW_IMPLEMENTATION)() {
  }
};

TEST_F(CLASSNAME(AllocatorTest, RMW_IMPLEMENTATION), allocator_shared_ptr) {
  initialize(false, "allocator_shared_ptr");
  size_t counter = 0;
  auto callback = [&counter](std_msgs::msg::UInt32::SharedPtr msg) -> void
    {
      EXPECT_EQ(counter, msg->data);
      counter++;
    };

  auto subscriber = node_->create_subscription<std_msgs::msg::UInt32>(
    "allocator_shared_ptr", 10, callback, nullptr, false, msg_memory_strategy_, alloc);
  // Create msg to be published
  auto msg = std::allocate_shared<std_msgs::msg::UInt32>(*alloc.get());

  rclcpp::utilities::sleep_for(std::chrono::milliseconds(1));
  // After test_initialization, global new should only be called from within TLSFAllocator.
  test_init = true;
  for (uint32_t i = 0; i < iterations; i++) {
    msg->data = i;
    publisher_->publish(msg);
    rclcpp::utilities::sleep_for(std::chrono::milliseconds(1));
    executor_->spin_some();
  }
  test_init = false;
  EXPECT_FALSE(fail);
  fail = false;
}

TEST_F(CLASSNAME(AllocatorTest, RMW_IMPLEMENTATION), allocator_unique_ptr) {
  initialize(true, "allocator_unique_ptr");
  size_t counter = 0;
  auto callback =
    [&counter](std_msgs::msg::UInt32::UniquePtrWithDeleter<UInt32Deleter> msg) -> void
    {
      EXPECT_EQ(counter, msg->data);
      counter++;
    };

  auto subscriber = node_->create_subscription<std_msgs::msg::UInt32>(
    "allocator_unique_ptr", 10, callback, nullptr, false, msg_memory_strategy_, alloc);

  TLSFAllocator<std_msgs::msg::UInt32> msg_alloc;

  rclcpp::utilities::sleep_for(std::chrono::milliseconds(1));
  // After test_initialization, global new should only be called from within TLSFAllocator.
  test_init = true;
  for (uint32_t i = 0; i < iterations; i++) {
    auto msg = std::unique_ptr<std_msgs::msg::UInt32, UInt32Deleter>(
      std::allocator_traits<UInt32Allocator>::allocate(msg_alloc, 1));
    msg->data = i;
    publisher_->publish(msg);
    rclcpp::utilities::sleep_for(std::chrono::milliseconds(1));
    executor_->spin_some();
  }
  test_init = false;
  EXPECT_FALSE(fail);
  fail = false;
}

void print_help()
{
  printf("--all-tokens: Do not ignore middleware tokens.\n");
  printf("--verbose: Report stack traces and allocation statistics.\n");
}

int main(int argc, char ** argv)
{
  rclcpp::init(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  // argc and argv are modified by InitGoogleTest
  std::vector<std::string> args(argv + 1, argv + argc);

  if (std::find(args.begin(), args.end(), "--help") != args.end()) {
    print_help();
    return 0;
  }
  verbose = std::find(args.begin(), args.end(), "--verbose") != args.end();
  ignore_middleware_tokens = std::find(args.begin(), args.end(), "--all-tokens") == args.end();

  return RUN_ALL_TESTS();
}
<|endoftext|>