<commit_before>/// \file ROOT/RError.h
/// \ingroup Base ROOT7
/// \author Jakob Blomer <jblomer@cern.ch>
/// \date 2019-12-11
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT7_RError
#define ROOT7_RError

#include <ROOT/RConfig.hxx> // for R__[un]likely
#include <ROOT/RLogger.hxx> // for R__LOG_PRETTY_FUNCTION

#include <cstddef>
#include <memory>
#include <new>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>

// The RResult<T> class and their related classes are used for call chains that can throw exceptions,
// such as I/O code paths.  Throwing of the exception is deferred to allow for `if (result)` style error
// checking where it makes sense.
//
// A function returning an RResult might look like this:
//
//     RResult<int> MyIOFunc()
//     {
//        int rv = syscall(...);
//        if (rv == -1)
//           return R__FAIL("user-facing error message");
//        if (rv == kShortcut)
//           return 42;
//        return R__FORWARD_RESULT(FuncThatReturnsRResultOfInt());
//     }
//
// Code using MyIOFunc might look like this:
//
//     auto result = MyIOOperation();
//     if (!result) {
//        /* custom error handling or result.Throw() */
//     }
//     switch (result.Inspect()) {
//        ...
//     }
//
// Note that RResult<void> can be used for a function without return value, like this
//
//     RResult<void> DoSomething()
//     {
//        if (failure)
//           return R__FAIL("user-facing error messge");
//        return RResult<void>::Success();
//     }

namespace ROOT {
namespace Experimental {

// clang-format off
/**
\class ROOT::Experimental::RError
\ingroup Base
\brief Captures diagnostics related to a ROOT runtime error
*/
// clang-format on
class RError {
public:
   struct RLocation {
      RLocation() = default;
      RLocation(const char *func, const char *file, int line)
         : fFunction(func), fSourceFile(file), fSourceLine(line) {}

      // TODO(jblomer) use std::source_location once available
      const char *fFunction;
      const char *fSourceFile;
      int fSourceLine;
   };

private:
   /// User-facing error message
   std::string fMessage;
   /// The location of the error related to fMessage plus upper frames if the error is forwarded through the call stack
   std::vector<RLocation> fStackTrace;

public:
   /// Used by R__FAIL
   RError(const std::string &message, RLocation &&sourceLocation);
   /// Used by R__FORWARD_RESULT
   void AddFrame(RLocation &&sourceLocation);
   /// Add more information to the diagnostics
   void AppendToMessage(const std::string &info) { fMessage += info; }
   /// Format a dignostics report, e.g. for an exception message
   std::string GetReport() const;
   const std::vector<RLocation> &GetStackTrace() const { return fStackTrace; }
};

// clang-format off
/**
\class ROOT::Experimental::RException
\ingroup Base
\brief Base class for all ROOT issued exceptions
*/
// clang-format on
class RException : public std::runtime_error {
   RError fError;
public:
   explicit RException(const RError &error) : std::runtime_error(error.GetReport()), fError(error) {}
   const RError &GetError() const { return fError; }
};

namespace Internal {
// clang-format off
/**
\class ROOT::Experimental::Internal::RResultBase
\ingroup Base
\brief Common handling of the error case for RResult<T> (T != void) and RResult<void>

RResultBase captures a possible runtime error that might have occured.  If the RResultBase leaves the scope unchecked,
it will throw an exception.  RResultBase should only be allocated on the stack, which is helped by deleting the
new operator.  RResultBase is movable but not copyable to avoid throwing multiple exceptions about the same failure.
*/
// clang-format on
class RResultBase {
protected:
   /// This is the nullptr for an RResult representing success
   std::unique_ptr<RError> fError;
   /// Switches to true once the user of an RResult object checks the object status
   bool fIsChecked{false};

   RResultBase() = default;
   explicit RResultBase(RError &&error) : fError(std::make_unique<RError>(std::move(error))) {}

   /// Used by the RResult<T> bool operator
   bool Check() {
      fIsChecked = true;
      return !fError;
   }

public:
   RResultBase(const RResultBase &other) = delete;
   RResultBase(RResultBase &&other) = default;
   RResultBase &operator =(const RResultBase &other) = delete;
   RResultBase &operator =(RResultBase &&other) = default;

   ~RResultBase() noexcept(false);

   RError *GetError() { return fError.get(); }
   /// Throws an RException with fError
   void Throw();

   // Help to prevent heap construction of RResult objects. Unchecked RResult objects in failure state should throw
   // an exception close to the error location. For stack allocated RResult objects, an exception is thrown
   // the latest when leaving the scope. Heap allocated RResult objects in failure state can live much longer making it
   // difficult to trace back the original error.
   void *operator new(std::size_t size) = delete;
   void *operator new(std::size_t, void *) = delete;
   void *operator new[](std::size_t) = delete;
   void *operator new[](std::size_t, void *) = delete;
}; // class RResultBase
} // namespace Internal

// clang-format off
/**
\class ROOT::Experimental::RResult
\ingroup Base
\brief The class is used as a return type for operations that can fail; wraps a value of type T or an RError

RResult enforces checking whether it contains a valid value or an error state. If the RResult leaves the scope
unchecked, it will throw an exception (due to ~RResultBase).
*/
// clang-format on
template <typename T>
class RResult : public Internal::RResultBase {
private:
   /// The result value in case of successful execution
   T fValue;

   // Ensure accessor methods throw in case of errors
   inline void ThrowOnError() {
      if (R__unlikely(fError)) {
         // Accessors can be wrapped in a try-catch block, so throwing the
         // exception here is akin to checking the error.
         //
         // Setting fIsChecked to true also avoids a spurious warning in the RResult destructor
         fIsChecked = true;

         fError->AppendToMessage(" (unchecked RResult access!)");
         throw RException(*fError);
      }
   }

public:
   RResult(const T &value) : fValue(value) {}
   RResult(T &&value) : fValue(std::move(value)) {}
   RResult(RError &&error) : RResultBase(std::move(error)) {}

   RResult(const RResult &other) = delete;
   RResult(RResult &&other) = default;
   RResult &operator =(const RResult &other) = delete;
   RResult &operator =(RResult &&other) = default;

   ~RResult() = default;

   /// Used by R__FORWARD_RESULT in order to keep track of the stack trace in case of errors
   static RResult &Forward(RResult &result, RError::RLocation &&sourceLocation) {
      if (result.fError)
         result.fError->AddFrame(std::move(sourceLocation));
      return result;
   }

   /// If the operation was successful, returns a const reference to the inner type.
   /// If there was an error, Inspect() instead throws an exception.
   const T &Inspect() {
      ThrowOnError();
      return fValue;
   }

   /// If the operation was successful, returns the inner type by value.
   ///
   /// For move-only types, Unwrap can only be called once, as it yields ownership of
   /// the inner value to the caller using std::move, potentially leaving the
   /// RResult in an unspecified state.
   ///
   /// If there was an error, Unwrap() instead throws an exception.
   T Unwrap() {
      ThrowOnError();
      return std::move(fValue);
   }

   explicit operator bool() { return Check(); }
};

/// RResult<void> has no data member and no Inspect() method but instead a Success() factory method
template<>
class RResult<void> : public Internal::RResultBase {
private:
   RResult() = default;

public:
   /// Returns a RResult<void> that captures the successful execution of the function
   static RResult Success() { return RResult(); }
   RResult(RError &&error) : RResultBase(std::move(error)) {}

   RResult(const RResult &other) = delete;
   RResult(RResult &&other) = default;
   RResult &operator =(const RResult &other) = delete;
   RResult &operator =(RResult &&other) = default;

   ~RResult() = default;

   /// Used by R__FORWARD_RESULT in order to keep track of the stack trace in case of errors
   static RResult &Forward(RResult &result, RError::RLocation &&sourceLocation) {
      if (result.fError)
         result.fError->AddFrame(std::move(sourceLocation));
      return result;
   }

   /// Short-hand method to throw an exception in the case of errors. Does nothing for
   /// successful RResults.
   void ThrowOnError() {
      if (!Check())
         Throw();
   }

   explicit operator bool() { return Check(); }
};

/// Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult<T>
#define R__FAIL(msg) ROOT::Experimental::RError(msg, {R__LOG_PRETTY_FUNCTION, __FILE__, __LINE__})
/// Short-hand to return an RResult<T> value from a subroutine to the calling stack frame
#define R__FORWARD_RESULT(res) std::move(res.Forward(res, {R__LOG_PRETTY_FUNCTION, __FILE__, __LINE__}))
} // namespace Experimental
} // namespace ROOT

#endif
<commit_msg>Simplify RResult::Forward() and R__FORWARD_RESULT<commit_after>/// \file ROOT/RError.h
/// \ingroup Base ROOT7
/// \author Jakob Blomer <jblomer@cern.ch>
/// \date 2019-12-11
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT7_RError
#define ROOT7_RError

#include <ROOT/RConfig.hxx> // for R__[un]likely
#include <ROOT/RLogger.hxx> // for R__LOG_PRETTY_FUNCTION

#include <cstddef>
#include <memory>
#include <new>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>

// The RResult<T> class and their related classes are used for call chains that can throw exceptions,
// such as I/O code paths.  Throwing of the exception is deferred to allow for `if (result)` style error
// checking where it makes sense.
//
// A function returning an RResult might look like this:
//
//     RResult<int> MyIOFunc()
//     {
//        int rv = syscall(...);
//        if (rv == -1)
//           return R__FAIL("user-facing error message");
//        if (rv == kShortcut)
//           return 42;
//        return R__FORWARD_RESULT(FuncThatReturnsRResultOfInt());
//     }
//
// Code using MyIOFunc might look like this:
//
//     auto result = MyIOOperation();
//     if (!result) {
//        /* custom error handling or result.Throw() */
//     }
//     switch (result.Inspect()) {
//        ...
//     }
//
// Note that RResult<void> can be used for a function without return value, like this
//
//     RResult<void> DoSomething()
//     {
//        if (failure)
//           return R__FAIL("user-facing error messge");
//        return RResult<void>::Success();
//     }

namespace ROOT {
namespace Experimental {

// clang-format off
/**
\class ROOT::Experimental::RError
\ingroup Base
\brief Captures diagnostics related to a ROOT runtime error
*/
// clang-format on
class RError {
public:
   struct RLocation {
      RLocation() = default;
      RLocation(const char *func, const char *file, int line)
         : fFunction(func), fSourceFile(file), fSourceLine(line) {}

      // TODO(jblomer) use std::source_location once available
      const char *fFunction;
      const char *fSourceFile;
      int fSourceLine;
   };

private:
   /// User-facing error message
   std::string fMessage;
   /// The location of the error related to fMessage plus upper frames if the error is forwarded through the call stack
   std::vector<RLocation> fStackTrace;

public:
   /// Used by R__FAIL
   RError(const std::string &message, RLocation &&sourceLocation);
   /// Used by R__FORWARD_RESULT
   void AddFrame(RLocation &&sourceLocation);
   /// Add more information to the diagnostics
   void AppendToMessage(const std::string &info) { fMessage += info; }
   /// Format a dignostics report, e.g. for an exception message
   std::string GetReport() const;
   const std::vector<RLocation> &GetStackTrace() const { return fStackTrace; }
};

// clang-format off
/**
\class ROOT::Experimental::RException
\ingroup Base
\brief Base class for all ROOT issued exceptions
*/
// clang-format on
class RException : public std::runtime_error {
   RError fError;
public:
   explicit RException(const RError &error) : std::runtime_error(error.GetReport()), fError(error) {}
   const RError &GetError() const { return fError; }
};

namespace Internal {
// clang-format off
/**
\class ROOT::Experimental::Internal::RResultBase
\ingroup Base
\brief Common handling of the error case for RResult<T> (T != void) and RResult<void>

RResultBase captures a possible runtime error that might have occured.  If the RResultBase leaves the scope unchecked,
it will throw an exception.  RResultBase should only be allocated on the stack, which is helped by deleting the
new operator.  RResultBase is movable but not copyable to avoid throwing multiple exceptions about the same failure.
*/
// clang-format on
class RResultBase {
protected:
   /// This is the nullptr for an RResult representing success
   std::unique_ptr<RError> fError;
   /// Switches to true once the user of an RResult object checks the object status
   bool fIsChecked{false};

   RResultBase() = default;
   explicit RResultBase(RError &&error) : fError(std::make_unique<RError>(std::move(error))) {}

   /// Used by the RResult<T> bool operator
   bool Check() {
      fIsChecked = true;
      return !fError;
   }

public:
   RResultBase(const RResultBase &other) = delete;
   RResultBase(RResultBase &&other) = default;
   RResultBase &operator =(const RResultBase &other) = delete;
   RResultBase &operator =(RResultBase &&other) = default;

   ~RResultBase() noexcept(false);

   RError *GetError() { return fError.get(); }
   /// Throws an RException with fError
   void Throw();

   // Help to prevent heap construction of RResult objects. Unchecked RResult objects in failure state should throw
   // an exception close to the error location. For stack allocated RResult objects, an exception is thrown
   // the latest when leaving the scope. Heap allocated RResult objects in failure state can live much longer making it
   // difficult to trace back the original error.
   void *operator new(std::size_t size) = delete;
   void *operator new(std::size_t, void *) = delete;
   void *operator new[](std::size_t) = delete;
   void *operator new[](std::size_t, void *) = delete;
}; // class RResultBase
} // namespace Internal

// clang-format off
/**
\class ROOT::Experimental::RResult
\ingroup Base
\brief The class is used as a return type for operations that can fail; wraps a value of type T or an RError

RResult enforces checking whether it contains a valid value or an error state. If the RResult leaves the scope
unchecked, it will throw an exception (due to ~RResultBase).
*/
// clang-format on
template <typename T>
class RResult : public Internal::RResultBase {
private:
   /// The result value in case of successful execution
   T fValue;

   // Ensure accessor methods throw in case of errors
   inline void ThrowOnError() {
      if (R__unlikely(fError)) {
         // Accessors can be wrapped in a try-catch block, so throwing the
         // exception here is akin to checking the error.
         //
         // Setting fIsChecked to true also avoids a spurious warning in the RResult destructor
         fIsChecked = true;

         fError->AppendToMessage(" (unchecked RResult access!)");
         throw RException(*fError);
      }
   }

public:
   RResult(const T &value) : fValue(value) {}
   RResult(T &&value) : fValue(std::move(value)) {}
   RResult(RError &&error) : RResultBase(std::move(error)) {}

   RResult(const RResult &other) = delete;
   RResult(RResult &&other) = default;
   RResult &operator =(const RResult &other) = delete;
   RResult &operator =(RResult &&other) = default;

   ~RResult() = default;

   /// Used by R__FORWARD_RESULT in order to keep track of the stack trace in case of errors
   RResult &Forward(RError::RLocation &&sourceLocation) {
      if (fError)
         fError->AddFrame(std::move(sourceLocation));
      return *this;
   }

   /// If the operation was successful, returns a const reference to the inner type.
   /// If there was an error, Inspect() instead throws an exception.
   const T &Inspect() {
      ThrowOnError();
      return fValue;
   }

   /// If the operation was successful, returns the inner type by value.
   ///
   /// For move-only types, Unwrap can only be called once, as it yields ownership of
   /// the inner value to the caller using std::move, potentially leaving the
   /// RResult in an unspecified state.
   ///
   /// If there was an error, Unwrap() instead throws an exception.
   T Unwrap() {
      ThrowOnError();
      return std::move(fValue);
   }

   explicit operator bool() { return Check(); }
};

/// RResult<void> has no data member and no Inspect() method but instead a Success() factory method
template<>
class RResult<void> : public Internal::RResultBase {
private:
   RResult() = default;

public:
   /// Returns a RResult<void> that captures the successful execution of the function
   static RResult Success() { return RResult(); }
   RResult(RError &&error) : RResultBase(std::move(error)) {}

   RResult(const RResult &other) = delete;
   RResult(RResult &&other) = default;
   RResult &operator =(const RResult &other) = delete;
   RResult &operator =(RResult &&other) = default;

   ~RResult() = default;

   /// Used by R__FORWARD_RESULT in order to keep track of the stack trace in case of errors
   RResult &Forward(RError::RLocation &&sourceLocation) {
      if (fError)
         fError->AddFrame(std::move(sourceLocation));
      return *this;
   }

   /// Short-hand method to throw an exception in the case of errors. Does nothing for
   /// successful RResults.
   void ThrowOnError() {
      if (!Check())
         Throw();
   }

   explicit operator bool() { return Check(); }
};

/// Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult<T>
#define R__FAIL(msg) ROOT::Experimental::RError(msg, {R__LOG_PRETTY_FUNCTION, __FILE__, __LINE__})
/// Short-hand to return an RResult<T> value from a subroutine to the calling stack frame
#define R__FORWARD_RESULT(res) std::move(res.Forward({R__LOG_PRETTY_FUNCTION, __FILE__, __LINE__}))
} // namespace Experimental
} // namespace ROOT

#endif
<|endoftext|>


<commit_before>/*
 * DefinitionIndex.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "DefinitionIndex.hpp"

#include <deque>

#include <core/FilePath.hpp>
#include <core/PerformanceTimer.hpp>
#include <core/libclang/LibClang.hpp>
#include <core/system/ProcessArgs.hpp>
#include <session/IncrementalFileChangeHandler.hpp>

#include <session/SessionModuleContext.hpp>
#include <session/projects/SessionProjects.hpp>

#include "RSourceIndex.hpp"
#include "RCompilationDatabase.hpp"

using namespace core;
using namespace core::libclang;

namespace session {
namespace modules {
namespace clang {

namespace {

// flag indicating whether we are initialized
bool s_initialized = false;

// store definitions by file
typedef std::map<std::string,std::deque<CppDefinition> > DefinitionsByFile;
DefinitionsByFile s_definitionsByFile;

// visitor used to populate deque
bool insertDefinition(const CppDefinition& definition,
                      std::deque<CppDefinition>* pDefinitions)
{
   pDefinitions->push_back(definition);
   return true;
}

bool isIndexableFile(const FileInfo& fileInfo,
                     const FilePath& pkgSrcDir,
                     const FilePath& pkgIncludeDir)
{
   FilePath filePath(fileInfo.absolutePath());

   if (pkgSrcDir.exists() &&
       filePath.isWithin(pkgSrcDir) &&
       SourceIndex::isSourceFile(filePath) &&
       !boost::algorithm::starts_with(filePath.stem(), kCompilationDbPrefix) &&
       (filePath.filename() != "RcppExports.cpp"))
   {
      return true;
   }
   else if (pkgIncludeDir.exists() &&
            filePath.isWithin(pkgIncludeDir) &&
            SourceIndex::isSourceFile(filePath) &&
            !boost::algorithm::ends_with(filePath.stem(), "_RcppExports"))
   {
      return true;
   }
   else
   {
      return false;
   }
}

typedef boost::function<bool(const CppDefinition&)> DefinitionVisitor;

CXChildVisitResult cursorVisitor(CXCursor cxCursor,
                                 CXCursor,
                                 CXClientData clientData)
{
   // get the cursor and check if it's in the right file
   Cursor cursor(cxCursor);
   SourceLocation location = cursor.getSourceLocation();
   if (!location.isFromMainFile())
      return CXChildVisit_Continue;

   // ensure it's a definition with external linkage
   if (!cursor.isDefinition() || !cursor.hasExternalLinkage())
      return CXChildVisit_Continue;

   // determine kind
   CppDefinitionKind kind = CppInvalidDefinition;
   switch (cursor.getKind())
   {
      case CXCursor_Namespace:
         kind = CppNamespaceDefinition;
         break;
      case CXCursor_ClassDecl:
      case CXCursor_ClassTemplate:
         kind = CppClassDefinition;
         break;
      case CXCursor_StructDecl:
         kind = CppStructDefinition;
         break;
      case CXCursor_EnumDecl:
         kind = CppEnumDefinition;
         break;
      case CXCursor_FunctionDecl:
      case CXCursor_FunctionTemplate:
         kind = CppFunctionDefinition;
         break;
      case CXCursor_CXXMethod:
         kind = CppMemberFunctionDefinition;
         break;
      default:
         kind = CppInvalidDefinition;
         break;
   }

   // continue if this isn't a definition of interest
   if (kind == CppInvalidDefinition)
      return CXChildVisit_Continue;

   // build name (strip trailing parens)
   std::string name = cursor.displayName();
   boost::algorithm::replace_last(name, "()", "");

   // empty display name for a namespace === anonymous
   if ((kind == CppNamespaceDefinition) && name.empty())
   {
      name = "<anonymous>";
   }

   // qualify class members
   std::string parentName;
   if (kind == CppMemberFunctionDefinition)
   {
      Cursor parent = cursor.getSemanticParent();
      parentName = parent.displayName();
   }

   // get the source location
   SourceLocation loc = cursor.getSourceLocation();
   std::string file;
   unsigned line, column;
   loc.getSpellingLocation(&file, &line, &column);

   // create the definition
   CppDefinition definition(cursor.getUSR(),
                            kind,
                            parentName,
                            name,
                            FileLocation(FilePath(file), line, column));

   // yield the definition (break if requested)
   DefinitionVisitor& visitor = *((DefinitionVisitor*)clientData);
   if (!visitor(definition))
      return CXChildVisit_Break;

   // recurse if necessary
   if (kind == CppNamespaceDefinition ||
       kind == CppClassDefinition ||
       kind == CppStructDefinition)
   {
      return CXChildVisit_Recurse;
   }
   else
   {
      return CXChildVisit_Continue;
   }
}

void fileChangeHandler(const core::system::FileChangeEvent& event)
{
   // always remove existing definitions
   std::string file = event.fileInfo().absolutePath();
   s_definitionsByFile.erase(file);

   // if this is an add or an update then re-index
   if (event.type() == core::system::FileChangeEvent::FileAdded ||
       event.type() == core::system::FileChangeEvent::FileModified)
   {
      // get the compilation arguments for this file and use them to
      // create a translation unit
      std::vector<std::string> compileArgs =
         rCompilationDatabase().compileArgsForTranslationUnit(file);

      if (!compileArgs.empty())
      {
         // create index
         CXIndex index = libclang::clang().createIndex(
                                             1 /* Exclude PCH */,
                                             0 /* No diagnostics */);

         // get args in form clang expects
         core::system::ProcessArgs argsArray(compileArgs);

         // parse the translation unit
         CXTranslationUnit tu = libclang::clang().parseTranslationUnit(
                               index,
                               file.c_str(),
                               argsArray.args(),
                               argsArray.argCount(),
                               NULL, 0, // no unsaved files
                               CXTranslationUnit_None |
                               CXTranslationUnit_Incomplete);

         // create deque of definitions and wire visitor to it
         s_definitionsByFile[file] = std::deque<CppDefinition>();
         DefinitionVisitor visitor =
            boost::bind(insertDefinition, _1, &s_definitionsByFile[file]);

         // visit the cursors
         libclang::clang().visitChildren(
              libclang::clang().getTranslationUnitCursor(tu),
              cursorVisitor,
              (CXClientData)&visitor);

         // dispose translation unit and index
         libclang::clang().disposeTranslationUnit(tu);
         libclang::clang().disposeIndex(index);
      }
   }
}

} // anonymous namespace

std::ostream& operator<<(std::ostream& os, const CppDefinition& definition)
{
   // kind
   std::string kindStr;
   switch (definition.kind)
   {
      case CppNamespaceDefinition:
         kindStr = "N";
         break;
      case CppClassDefinition:
         kindStr = "C";
         break;
      case CppStructDefinition:
         kindStr = "S";
         break;
      case CppEnumDefinition:
         kindStr = "E";
         break;
      case CppFunctionDefinition:
         kindStr = "F";
         break;
      case CppMemberFunctionDefinition:
         kindStr = "M";
         break;
      default:
         kindStr = " ";
         break;
   }
   os << "[" << kindStr << "] ";

   // display name
   if (!definition.parentName.empty())
      os << definition.parentName << "::";
   os << definition.name << " ";

   // file location
   os << "(" << definition.location.filePath.filename() << ":"
      << definition.location.line << ":" << definition.location.column << ") ";

   // USR
   os << definition.USR;

   return os;
}

namespace {

bool findUSR(const std::string& USR,
             const CppDefinition& definition,
             CppDefinition* pFoundDefinition)
{
   if (definition.USR == USR)
   {
      *pFoundDefinition = definition;
      return false;
   }
   else
   {
      return true;
   }
}

typedef std::map<std::string,CXTranslationUnit> TranslationUnits;

} // anonymous namespace

FileLocation findDefinitionLocation(const FileLocation& location)
{
   // bail if we aren't initialized
   if (!s_initialized)
      return FileLocation();

   // get the translation unit
   std::string filename = location.filePath.absolutePath();
   TranslationUnit tu = rSourceIndex().getTranslationUnit(filename, true);
   if (tu.empty())
      return FileLocation();

   // get the cursor
   Cursor cursor = tu.getCursor(filename, location.line, location.column);
   if (!cursor.isValid())
      return FileLocation();

   // follow reference if we need to
   if (cursor.isReference() || cursor.isExpression())
   {
      cursor = cursor.getReferenced();
      if (!cursor.isValid())
         return FileLocation();
   }

   // get the USR for the cursor and search for it
   std::string USR = cursor.getUSR();
   if (!USR.empty())
   {
      // first inspect translation units we have an in-memory index for
      TranslationUnits units = rSourceIndex().getIndexedTranslationUnits();
      BOOST_FOREACH(const TranslationUnits::value_type& unit, units)
      {
         // search for the definition
         CppDefinition def;
         DefinitionVisitor visitor = boost::bind(findUSR, USR, _1, &def);

         // visit the cursors
         libclang::clang().visitChildren(
              libclang::clang().getTranslationUnitCursor(unit.second),
              cursorVisitor,
              (CXClientData)&visitor);

         // return the definition if we found it
         if (!def.empty())
            return def.location;
      }

      // if we didn't find it there then look for it in our index
      // of all saved files
      BOOST_FOREACH(const DefinitionsByFile::value_type& defs,
                    s_definitionsByFile)
      {
         BOOST_FOREACH(const CppDefinition& def, defs.second)
         {
            if (def.USR == USR)
               return def.location;
         }
      }
   }

   // see if we can resolve the cursor to a definition (if we can't
   // that's okay)
   if (!cursor.isDefinition())
   {
      Cursor cursorDef = cursor.getDefinition();
      if (cursorDef.isValid())
         cursor = cursorDef;
   }

   // return the location
   SourceLocation loc = cursor.getSourceLocation();
   unsigned line, column;
   loc.getSpellingLocation(&filename, &line, &column);
   return FileLocation(FilePath(filename), line, column);
}

namespace {

bool matches(const std::string& term,
             const boost::regex& pattern,
             const CppDefinition& definition)
{
   if (!pattern.empty())
      return regex_utils::textMatches(definition.name, pattern, false, false);
   else
      return string_utils::isSubsequence(definition.name, term, true);
}

bool insertMatching(const std::string& term,
                    const boost::regex& pattern,
                    const CppDefinition& definition,
                    std::vector<CppDefinition>* pDefinitions)
{
   if (matches(term, pattern, definition))
      pDefinitions->push_back(definition);
   return true;
}

} // anonymous namespace

void searchDefinitions(const std::string& term,
                       std::vector<CppDefinition>* pDefinitions)
{
   // bail if we aren't initialized
   if (!s_initialized)
      return;

   // get a pattern for the term (if it includes a wildcard '*')
   boost::regex pattern = regex_utils::regexIfWildcardPattern(term);

   // first search translation units we have an in-memory index for
   // (this will reflect unsaved changes in editor buffers)
   TranslationUnits units = rSourceIndex().getIndexedTranslationUnits();
   BOOST_FOREACH(const TranslationUnits::value_type& unit, units)
   {
      // search for matching definitions
      DefinitionVisitor visitor =
         boost::bind(insertMatching, term, pattern, _1, pDefinitions);

      // visit the cursors
      libclang::clang().visitChildren(
           libclang::clang().getTranslationUnitCursor(unit.second),
           cursorVisitor,
           (CXClientData)&visitor);
   }

   // now search the project index (excluding files we already searched
   // for within the in-memory index)
   // if we didn't find it there then look for it in our index
   // of all saved files
   BOOST_FOREACH(const DefinitionsByFile::value_type& defs, s_definitionsByFile)
   {
      // skip files we've already searched
      if (units.find(defs.first) != units.end())
         continue;

      BOOST_FOREACH(const CppDefinition& def, defs.second)
      {
         if (matches(term, pattern, def))
            pDefinitions->push_back(def);
      }
   }
}

Error initializeDefinitionIndex()
{
   using namespace projects;
   if (projectContext().config().buildType == r_util::kBuildTypePackage)
   {
      // check for src and inst/include dirs
      FilePath pkgPath = projects::projectContext().buildTargetPath();
      FilePath srcPath = pkgPath.childPath("src");
      FilePath includePath = pkgPath.childPath("inst/include");
      if (srcPath.exists() || includePath.exists())
      {
         // create an incremental file change handler (on the heap so that it
         // survives the call to this function and is never deleted)
         IncrementalFileChangeHandler* pFileChangeHandler =
           new IncrementalFileChangeHandler(
                  boost::bind(isIndexableFile, _1, srcPath, includePath),
                  fileChangeHandler,
                  boost::posix_time::milliseconds(200),
                  boost::posix_time::milliseconds(20),
                  true);
         pFileChangeHandler->subscribeToFileMonitor("Go to C/C++ Definition");
      }

      // set initialized flag
      s_initialized = true;
   }

   return Success();
}

} // namespace clang
} // namespace modules
} // namesapce session

<commit_msg>don't include namespaces in definition index<commit_after>/*
 * DefinitionIndex.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "DefinitionIndex.hpp"

#include <deque>

#include <core/FilePath.hpp>
#include <core/PerformanceTimer.hpp>
#include <core/libclang/LibClang.hpp>
#include <core/system/ProcessArgs.hpp>
#include <session/IncrementalFileChangeHandler.hpp>

#include <session/SessionModuleContext.hpp>
#include <session/projects/SessionProjects.hpp>

#include "RSourceIndex.hpp"
#include "RCompilationDatabase.hpp"

using namespace core;
using namespace core::libclang;

namespace session {
namespace modules {
namespace clang {

namespace {

// flag indicating whether we are initialized
bool s_initialized = false;

// store definitions by file
typedef std::map<std::string,std::deque<CppDefinition> > DefinitionsByFile;
DefinitionsByFile s_definitionsByFile;

// visitor used to populate deque
bool insertDefinition(const CppDefinition& definition,
                      std::deque<CppDefinition>* pDefinitions)
{
   pDefinitions->push_back(definition);
   return true;
}

bool isIndexableFile(const FileInfo& fileInfo,
                     const FilePath& pkgSrcDir,
                     const FilePath& pkgIncludeDir)
{
   FilePath filePath(fileInfo.absolutePath());

   if (pkgSrcDir.exists() &&
       filePath.isWithin(pkgSrcDir) &&
       SourceIndex::isSourceFile(filePath) &&
       !boost::algorithm::starts_with(filePath.stem(), kCompilationDbPrefix) &&
       (filePath.filename() != "RcppExports.cpp"))
   {
      return true;
   }
   else if (pkgIncludeDir.exists() &&
            filePath.isWithin(pkgIncludeDir) &&
            SourceIndex::isSourceFile(filePath) &&
            !boost::algorithm::ends_with(filePath.stem(), "_RcppExports"))
   {
      return true;
   }
   else
   {
      return false;
   }
}

typedef boost::function<bool(const CppDefinition&)> DefinitionVisitor;

CXChildVisitResult cursorVisitor(CXCursor cxCursor,
                                 CXCursor,
                                 CXClientData clientData)
{
   // get the cursor and check if it's in the right file
   Cursor cursor(cxCursor);
   SourceLocation location = cursor.getSourceLocation();
   if (!location.isFromMainFile())
      return CXChildVisit_Continue;

   // ensure it's a definition with external linkage
   if (!cursor.isDefinition() || !cursor.hasExternalLinkage())
      return CXChildVisit_Continue;

   // determine kind
   CppDefinitionKind kind = CppInvalidDefinition;
   switch (cursor.getKind())
   {
      case CXCursor_ClassDecl:
      case CXCursor_ClassTemplate:
         kind = CppClassDefinition;
         break;
      case CXCursor_StructDecl:
         kind = CppStructDefinition;
         break;
      case CXCursor_EnumDecl:
         kind = CppEnumDefinition;
         break;
      case CXCursor_FunctionDecl:
      case CXCursor_FunctionTemplate:
         kind = CppFunctionDefinition;
         break;
      case CXCursor_CXXMethod:
         kind = CppMemberFunctionDefinition;
         break;
      default:
         kind = CppInvalidDefinition;
         break;
   }

   // continue if this isn't a definition of interest
   if (kind == CppInvalidDefinition)
      return CXChildVisit_Continue;

   // build name (strip trailing parens)
   std::string name = cursor.displayName();
   boost::algorithm::replace_last(name, "()", "");

   // empty display name for a namespace === anonymous
   if ((kind == CppNamespaceDefinition) && name.empty())
   {
      name = "<anonymous>";
   }

   // qualify class members
   std::string parentName;
   if (kind == CppMemberFunctionDefinition)
   {
      Cursor parent = cursor.getSemanticParent();
      parentName = parent.displayName();
   }

   // get the source location
   SourceLocation loc = cursor.getSourceLocation();
   std::string file;
   unsigned line, column;
   loc.getSpellingLocation(&file, &line, &column);

   // create the definition
   CppDefinition definition(cursor.getUSR(),
                            kind,
                            parentName,
                            name,
                            FileLocation(FilePath(file), line, column));

   // yield the definition (break if requested)
   DefinitionVisitor& visitor = *((DefinitionVisitor*)clientData);
   if (!visitor(definition))
      return CXChildVisit_Break;

   // recurse if necessary
   if (kind == CppNamespaceDefinition ||
       kind == CppClassDefinition ||
       kind == CppStructDefinition)
   {
      return CXChildVisit_Recurse;
   }
   else
   {
      return CXChildVisit_Continue;
   }
}

void fileChangeHandler(const core::system::FileChangeEvent& event)
{
   // always remove existing definitions
   std::string file = event.fileInfo().absolutePath();
   s_definitionsByFile.erase(file);

   // if this is an add or an update then re-index
   if (event.type() == core::system::FileChangeEvent::FileAdded ||
       event.type() == core::system::FileChangeEvent::FileModified)
   {
      // get the compilation arguments for this file and use them to
      // create a translation unit
      std::vector<std::string> compileArgs =
         rCompilationDatabase().compileArgsForTranslationUnit(file);

      if (!compileArgs.empty())
      {
         // create index
         CXIndex index = libclang::clang().createIndex(
                                             1 /* Exclude PCH */,
                                             0 /* No diagnostics */);

         // get args in form clang expects
         core::system::ProcessArgs argsArray(compileArgs);

         // parse the translation unit
         CXTranslationUnit tu = libclang::clang().parseTranslationUnit(
                               index,
                               file.c_str(),
                               argsArray.args(),
                               argsArray.argCount(),
                               NULL, 0, // no unsaved files
                               CXTranslationUnit_None |
                               CXTranslationUnit_Incomplete);

         // create deque of definitions and wire visitor to it
         s_definitionsByFile[file] = std::deque<CppDefinition>();
         DefinitionVisitor visitor =
            boost::bind(insertDefinition, _1, &s_definitionsByFile[file]);

         // visit the cursors
         libclang::clang().visitChildren(
              libclang::clang().getTranslationUnitCursor(tu),
              cursorVisitor,
              (CXClientData)&visitor);

         // dispose translation unit and index
         libclang::clang().disposeTranslationUnit(tu);
         libclang::clang().disposeIndex(index);
      }
   }
}

} // anonymous namespace

std::ostream& operator<<(std::ostream& os, const CppDefinition& definition)
{
   // kind
   std::string kindStr;
   switch (definition.kind)
   {
      case CppNamespaceDefinition:
         kindStr = "N";
         break;
      case CppClassDefinition:
         kindStr = "C";
         break;
      case CppStructDefinition:
         kindStr = "S";
         break;
      case CppEnumDefinition:
         kindStr = "E";
         break;
      case CppFunctionDefinition:
         kindStr = "F";
         break;
      case CppMemberFunctionDefinition:
         kindStr = "M";
         break;
      default:
         kindStr = " ";
         break;
   }
   os << "[" << kindStr << "] ";

   // display name
   if (!definition.parentName.empty())
      os << definition.parentName << "::";
   os << definition.name << " ";

   // file location
   os << "(" << definition.location.filePath.filename() << ":"
      << definition.location.line << ":" << definition.location.column << ") ";

   // USR
   os << definition.USR;

   return os;
}

namespace {

bool findUSR(const std::string& USR,
             const CppDefinition& definition,
             CppDefinition* pFoundDefinition)
{
   if (definition.USR == USR)
   {
      *pFoundDefinition = definition;
      return false;
   }
   else
   {
      return true;
   }
}

typedef std::map<std::string,CXTranslationUnit> TranslationUnits;

} // anonymous namespace

FileLocation findDefinitionLocation(const FileLocation& location)
{
   // bail if we aren't initialized
   if (!s_initialized)
      return FileLocation();

   // get the translation unit
   std::string filename = location.filePath.absolutePath();
   TranslationUnit tu = rSourceIndex().getTranslationUnit(filename, true);
   if (tu.empty())
      return FileLocation();

   // get the cursor
   Cursor cursor = tu.getCursor(filename, location.line, location.column);
   if (!cursor.isValid())
      return FileLocation();

   // follow reference if we need to
   if (cursor.isReference() || cursor.isExpression())
   {
      cursor = cursor.getReferenced();
      if (!cursor.isValid())
         return FileLocation();
   }

   // get the USR for the cursor and search for it
   std::string USR = cursor.getUSR();
   if (!USR.empty())
   {
      // first inspect translation units we have an in-memory index for
      TranslationUnits units = rSourceIndex().getIndexedTranslationUnits();
      BOOST_FOREACH(const TranslationUnits::value_type& unit, units)
      {
         // search for the definition
         CppDefinition def;
         DefinitionVisitor visitor = boost::bind(findUSR, USR, _1, &def);

         // visit the cursors
         libclang::clang().visitChildren(
              libclang::clang().getTranslationUnitCursor(unit.second),
              cursorVisitor,
              (CXClientData)&visitor);

         // return the definition if we found it
         if (!def.empty())
            return def.location;
      }

      // if we didn't find it there then look for it in our index
      // of all saved files
      BOOST_FOREACH(const DefinitionsByFile::value_type& defs,
                    s_definitionsByFile)
      {
         BOOST_FOREACH(const CppDefinition& def, defs.second)
         {
            if (def.USR == USR)
               return def.location;
         }
      }
   }

   // see if we can resolve the cursor to a definition (if we can't
   // that's okay)
   if (!cursor.isDefinition())
   {
      Cursor cursorDef = cursor.getDefinition();
      if (cursorDef.isValid())
         cursor = cursorDef;
   }

   // return the location
   SourceLocation loc = cursor.getSourceLocation();
   unsigned line, column;
   loc.getSpellingLocation(&filename, &line, &column);
   return FileLocation(FilePath(filename), line, column);
}

namespace {

bool matches(const std::string& term,
             const boost::regex& pattern,
             const CppDefinition& definition)
{
   if (!pattern.empty())
      return regex_utils::textMatches(definition.name, pattern, false, false);
   else
      return string_utils::isSubsequence(definition.name, term, true);
}

bool insertMatching(const std::string& term,
                    const boost::regex& pattern,
                    const CppDefinition& definition,
                    std::vector<CppDefinition>* pDefinitions)
{
   if (matches(term, pattern, definition))
      pDefinitions->push_back(definition);
   return true;
}

} // anonymous namespace

void searchDefinitions(const std::string& term,
                       std::vector<CppDefinition>* pDefinitions)
{
   // bail if we aren't initialized
   if (!s_initialized)
      return;

   // get a pattern for the term (if it includes a wildcard '*')
   boost::regex pattern = regex_utils::regexIfWildcardPattern(term);

   // first search translation units we have an in-memory index for
   // (this will reflect unsaved changes in editor buffers)
   TranslationUnits units = rSourceIndex().getIndexedTranslationUnits();
   BOOST_FOREACH(const TranslationUnits::value_type& unit, units)
   {
      // search for matching definitions
      DefinitionVisitor visitor =
         boost::bind(insertMatching, term, pattern, _1, pDefinitions);

      // visit the cursors
      libclang::clang().visitChildren(
           libclang::clang().getTranslationUnitCursor(unit.second),
           cursorVisitor,
           (CXClientData)&visitor);
   }

   // now search the project index (excluding files we already searched
   // for within the in-memory index)
   // if we didn't find it there then look for it in our index
   // of all saved files
   BOOST_FOREACH(const DefinitionsByFile::value_type& defs, s_definitionsByFile)
   {
      // skip files we've already searched
      if (units.find(defs.first) != units.end())
         continue;

      BOOST_FOREACH(const CppDefinition& def, defs.second)
      {
         if (matches(term, pattern, def))
            pDefinitions->push_back(def);
      }
   }
}

Error initializeDefinitionIndex()
{
   using namespace projects;
   if (projectContext().config().buildType == r_util::kBuildTypePackage)
   {
      // check for src and inst/include dirs
      FilePath pkgPath = projects::projectContext().buildTargetPath();
      FilePath srcPath = pkgPath.childPath("src");
      FilePath includePath = pkgPath.childPath("inst/include");
      if (srcPath.exists() || includePath.exists())
      {
         // create an incremental file change handler (on the heap so that it
         // survives the call to this function and is never deleted)
         IncrementalFileChangeHandler* pFileChangeHandler =
           new IncrementalFileChangeHandler(
                  boost::bind(isIndexableFile, _1, srcPath, includePath),
                  fileChangeHandler,
                  boost::posix_time::milliseconds(200),
                  boost::posix_time::milliseconds(20),
                  true);
         pFileChangeHandler->subscribeToFileMonitor("Go to C/C++ Definition");
      }

      // set initialized flag
      s_initialized = true;
   }

   return Success();
}

} // namespace clang
} // namespace modules
} // namesapce session

<|endoftext|>


<commit_before>/*
 * DownloadUI.cpp
 *
 *  Created on: Oct 13, 2011
 *      Author: siarheirachytski
 */

#include <jni.h>
#include "Framework.hpp"
#include "DownloadUI.hpp"
#include "../jni/jni_thread.hpp"
#include "../../../../../std/bind.hpp"
#include "../../../../../base/logging.hpp"

android::DownloadUI * g_downloadUI = 0;

namespace android
{
  DownloadUI::DownloadUI(jobject self)
  {
    m_self = jni::GetCurrentThreadJNIEnv()->NewGlobalRef(self);

    jclass k = jni::GetCurrentThreadJNIEnv()->GetObjectClass(m_self);

    m_onChangeCountry.reset(new jni::Method(k, "onChangeCountry", "(III)V"));
    m_onProgress.reset(new jni::Method(k, "onProgress", "(IIIJJ)V"));

    ASSERT(!g_downloadUI, ());
    g_downloadUI = this;
  }

  DownloadUI::~DownloadUI()
  {
    jni::GetCurrentThreadJNIEnv()->DeleteGlobalRef(m_self);
    g_downloadUI = 0;
  }

  void DownloadUI::OnChangeCountry(storage::TIndex const & idx)
  {
    jint group = idx.m_group;
    jint country = idx.m_country;
    jint region = idx.m_region;

    LOG(LINFO, ("Changed Country", group, country, region));

    m_onChangeCountry->CallVoid(m_self, group, country, region);
  }

  void DownloadUI::OnProgress(storage::TIndex const & idx, pair<int64_t, int64_t> const & p)
  {
    jint group = idx.m_group;
    jint country = idx.m_country;
    jint region = idx.m_region;
    jlong p1 = p.first;
    jlong p2 = p.second;

    LOG(LINFO, ("Country Progress", group, country, region, p1, p2));

    m_onProgress->CallVoid(m_self, group, country, region, p1, p2);
  }
}

///////////////////////////////////////////////////////////////////////////////////
// DownloadUI
///////////////////////////////////////////////////////////////////////////////////

extern "C"
{
  JNIEXPORT void JNICALL
  Java_com_mapswithme_maps_DownloadUI_nativeCreate(JNIEnv * env, jobject thiz)
  {
    g_downloadUI = new android::DownloadUI(thiz);
    g_framework->Storage().Subscribe(bind(&android::DownloadUI::OnChangeCountry, g_downloadUI, _1),
                                     bind(&android::DownloadUI::OnProgress, g_downloadUI, _1, _2));
  }

  JNIEXPORT void JNICALL
  Java_com_mapswithme_maps_DownloadUI_nativeDestroy(JNIEnv * env, jobject thiz)
  {
    g_framework->Storage().Unsubscribe();
    delete g_downloadUI;
  }

  JNIEXPORT jint JNICALL
  Java_com_mapswithme_maps_DownloadUI_countriesCount(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    return static_cast<jint>(g_framework->Storage().CountriesCount(storage::TIndex(group, country, region)));
  }

  JNIEXPORT jstring JNICALL
  Java_com_mapswithme_maps_DownloadUI_countryName(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    string const name = g_framework->Storage().CountryName(storage::TIndex(group, country, region));
    return env->NewStringUTF(name.c_str());
  }

  JNIEXPORT jlong JNICALL
  Java_com_mapswithme_maps_DownloadUI_countryLocalSizeInBytes(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    storage::LocalAndRemoteSizeT const s = g_framework->Storage().CountrySizeInBytes(storage::TIndex(group, country, region));
    return s.first;
  }

  JNIEXPORT jlong JNICALL
  Java_com_mapswithme_maps_DownloadUI_countryRemoteSizeInBytes(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    storage::LocalAndRemoteSizeT const s = g_framework->Storage().CountrySizeInBytes(storage::TIndex(group, country, region));
    return s.second;
  }

  JNIEXPORT jint JNICALL
  Java_com_mapswithme_maps_DownloadUI_countryStatus(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    return static_cast<jint>(g_framework->Storage().CountryStatus(storage::TIndex(group, country, region)));
  }

  JNIEXPORT jint JNICALL
  Java_com_mapswithme_maps_DownloadUI_downloadCountry(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    g_framework->Storage().DownloadCountry(storage::TIndex(group, country, region));
  }

  JNIEXPORT jint JNICALL
  Java_com_mapswithme_maps_DownloadUI_deleteCountry(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    g_framework->Storage().DeleteCountry(storage::TIndex(group, country, region));
  }
}

<commit_msg>[android] Small trick for faster DownloadUI displaying - caching returned country size<commit_after>/*
 * DownloadUI.cpp
 *
 *  Created on: Oct 13, 2011
 *      Author: siarheirachytski
 */

#include <jni.h>
#include "Framework.hpp"
#include "DownloadUI.hpp"
#include "../jni/jni_thread.hpp"
#include "../../../../../std/bind.hpp"
#include "../../../../../base/logging.hpp"

android::DownloadUI * g_downloadUI = 0;

namespace android
{
  DownloadUI::DownloadUI(jobject self)
  {
    m_self = jni::GetCurrentThreadJNIEnv()->NewGlobalRef(self);

    jclass k = jni::GetCurrentThreadJNIEnv()->GetObjectClass(m_self);

    m_onChangeCountry.reset(new jni::Method(k, "onChangeCountry", "(III)V"));
    m_onProgress.reset(new jni::Method(k, "onProgress", "(IIIJJ)V"));

    ASSERT(!g_downloadUI, ());
    g_downloadUI = this;
  }

  DownloadUI::~DownloadUI()
  {
    jni::GetCurrentThreadJNIEnv()->DeleteGlobalRef(m_self);
    g_downloadUI = 0;
  }

  void DownloadUI::OnChangeCountry(storage::TIndex const & idx)
  {
    jint group = idx.m_group;
    jint country = idx.m_country;
    jint region = idx.m_region;

    LOG(LINFO, ("Changed Country", group, country, region));

    m_onChangeCountry->CallVoid(m_self, group, country, region);
  }

  void DownloadUI::OnProgress(storage::TIndex const & idx, pair<int64_t, int64_t> const & p)
  {
    jint group = idx.m_group;
    jint country = idx.m_country;
    jint region = idx.m_region;
    jlong p1 = p.first;
    jlong p2 = p.second;

    LOG(LINFO, ("Country Progress", group, country, region, p1, p2));

    m_onProgress->CallVoid(m_self, group, country, region, p1, p2);
  }
}

///////////////////////////////////////////////////////////////////////////////////
// DownloadUI
///////////////////////////////////////////////////////////////////////////////////

extern "C"
{
  JNIEXPORT void JNICALL
  Java_com_mapswithme_maps_DownloadUI_nativeCreate(JNIEnv * env, jobject thiz)
  {
    g_downloadUI = new android::DownloadUI(thiz);
    g_framework->Storage().Subscribe(bind(&android::DownloadUI::OnChangeCountry, g_downloadUI, _1),
                                     bind(&android::DownloadUI::OnProgress, g_downloadUI, _1, _2));
  }

  JNIEXPORT void JNICALL
  Java_com_mapswithme_maps_DownloadUI_nativeDestroy(JNIEnv * env, jobject thiz)
  {
    g_framework->Storage().Unsubscribe();
    delete g_downloadUI;
  }

  JNIEXPORT jint JNICALL
  Java_com_mapswithme_maps_DownloadUI_countriesCount(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    return static_cast<jint>(g_framework->Storage().CountriesCount(storage::TIndex(group, country, region)));
  }

  JNIEXPORT jstring JNICALL
  Java_com_mapswithme_maps_DownloadUI_countryName(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    string const name = g_framework->Storage().CountryName(storage::TIndex(group, country, region));
    return env->NewStringUTF(name.c_str());
  }

  // @TODO Small hack to save time by caching last file size
  storage::TIndex g_lastCountryIndex(storage::TIndex::INVALID);
  storage::LocalAndRemoteSizeT g_lastSize(-1, -1);

  JNIEXPORT jlong JNICALL
  Java_com_mapswithme_maps_DownloadUI_countryLocalSizeInBytes(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    storage::TIndex const index(group, country, region);
    if (index == g_lastCountryIndex)
      return g_lastSize.first;
    g_lastCountryIndex = index;
    g_lastSize = g_framework->Storage().CountrySizeInBytes(index);
    return g_lastSize.first;
  }

  JNIEXPORT jlong JNICALL
  Java_com_mapswithme_maps_DownloadUI_countryRemoteSizeInBytes(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    storage::TIndex const index(group, country, region);
    if (index == g_lastCountryIndex)
      return g_lastSize.second;
    g_lastCountryIndex = index;
    g_lastSize = g_framework->Storage().CountrySizeInBytes(index);
    return g_lastSize.second;
  }

  JNIEXPORT jint JNICALL
  Java_com_mapswithme_maps_DownloadUI_countryStatus(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    return static_cast<jint>(g_framework->Storage().CountryStatus(storage::TIndex(group, country, region)));
  }

  JNIEXPORT jint JNICALL
  Java_com_mapswithme_maps_DownloadUI_downloadCountry(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    g_framework->Storage().DownloadCountry(storage::TIndex(group, country, region));
  }

  JNIEXPORT jint JNICALL
  Java_com_mapswithme_maps_DownloadUI_deleteCountry(JNIEnv * env, jobject thiz,
      jint group, jint country, jint region)
  {
    g_framework->Storage().DeleteCountry(storage::TIndex(group, country, region));
  }
}

<|endoftext|>


<commit_before><commit_msg>Fix dyn_pmp_h<commit_after><|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2016, Balazs Racz
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file CC32xxEEPROMEmulation.cxx
 * This file implements EEPROM emulation on the CC32xx SPI-flash filesystem.
 *
 * @author Balazs Racz
 * @date 30 December 2016
 */

//#define LOGLEVEL VERBOSE
#define SUPPORT_SL_R1_API

#include "utils/logging.h"

#include "freertos_drivers/ti/CC32xxEEPROMEmulation.hxx"
#include "freertos_drivers/ti/CC32xxHelper.hxx"
#include "simplelink.h"
#include "fs.h"

const uint8_t CC32xxEEPROMEmulation::SECTOR_COUNT = 8;

extern "C" {
void eeprom_updated_notification();
}

CC32xxEEPROMEmulation::CC32xxEEPROMEmulation(
    const char *name, size_t file_size_bytes)
    : EEPROM(name, file_size_bytes)
{
    data_ = (uint8_t *)malloc(file_size_bytes);
    HASSERT(data_);
    memset(data_, 0xff, file_size_bytes);
}

void CC32xxEEPROMEmulation::mount()
{
    bool have_rot = false;
    // First we need to find what was the last written segment.
    for (unsigned sector = 0; sector < SECTOR_COUNT; ++sector)
    {
        int handle = open_file(sector, FS_MODE_OPEN_READ, true);
        if (handle < 0)
        {
            LOG(VERBOSE, "EEPROM: sector %u: could not open.", sector);
            continue;
        }
        unsigned b = 0xaa55aaaa;
        SlCheckResult(sl_FsRead(handle, 0, (uint8_t *)&b, 4), 4);
        sl_FsClose(handle, nullptr, nullptr, 0);
        LOG(VERBOSE, "EEPROM: sector %u: version %u.", sector, b);
        if (b >= fileVersion_)
        {
            readSector_ = sector;
            fileVersion_ = b;
            have_rot = true;
        }
    }

    if (have_rot)
    {
        LOG(VERBOSE, "EEPROM: read sector %u:", readSector_);
        int handle = open_file(readSector_, FS_MODE_OPEN_READ);
        int ret = sl_FsRead(handle, 4, data_, file_size());
        if (ret < 0)
        {
            SlCheckResult(ret);
        }
    } else {
        LOG(VERBOSE, "EEPROM: no read sector");
    }
}

CC32xxEEPROMEmulation::~CC32xxEEPROMEmulation()
{
    flush();
    free(data_);
}

void CC32xxEEPROMEmulation::flush_buffers()
{
    if (!isDirty_)
        return;
    ++fileVersion_;
    ++readSector_;
    if (readSector_ >= SECTOR_COUNT)
        readSector_ = 0;
    LOG(VERBOSE, "EEPROM: write sector %u version %u", readSector_, fileVersion_);
    int handle = open_file(readSector_, FS_MODE_OPEN_WRITE, true);
    if (handle < 0)
    {
        handle =
            open_file(readSector_, FS_MODE_OPEN_CREATE(file_size() + 4, 0));
    }
    SlCheckResult(sl_FsWrite(handle, 0, (uint8_t *)&fileVersion_, 4), 4);
    SlCheckResult(sl_FsWrite(handle, 4, data_, file_size()), file_size());
    SlCheckResult(sl_FsClose(handle, nullptr, nullptr, 0));
    isDirty_ = 0;
}

int CC32xxEEPROMEmulation::open_file(
    unsigned sector, uint32_t open_mode, bool ignore_error)
{
    string filename(name);
    filename.push_back('.');
    filename.push_back('0' + sector);
    int32_t handle = -1;
    int ret = sl_FsOpen((uint8_t *)filename.c_str(), open_mode, NULL, &handle);
    if (!ignore_error)
    {
        SlCheckResult(ret);
        HASSERT(handle >= 0);
    }
    return handle;
}

void CC32xxEEPROMEmulation::write(
    unsigned int index, const void *buf, size_t len)
{
    // Boundary checks are performed by the EEPROM class.
    if (memcmp(data_ + index, buf, len) == 0) {
        return;
    }
    memcpy(data_ + index, buf, len);
    isDirty_ = 1;
    eeprom_updated_notification();
}

void CC32xxEEPROMEmulation::read(unsigned int index, void *buf, size_t len)
{
    // Boundary checks are performed by the EEPROM class.
    memcpy(buf, data_ + index, len);
}
<commit_msg>Add missing file close.<commit_after>/** \copyright
 * Copyright (c) 2016, Balazs Racz
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file CC32xxEEPROMEmulation.cxx
 * This file implements EEPROM emulation on the CC32xx SPI-flash filesystem.
 *
 * @author Balazs Racz
 * @date 30 December 2016
 */

//#define LOGLEVEL VERBOSE
#define SUPPORT_SL_R1_API

#include "utils/logging.h"

#include "freertos_drivers/ti/CC32xxEEPROMEmulation.hxx"
#include "freertos_drivers/ti/CC32xxHelper.hxx"
#include "simplelink.h"
#include "fs.h"

const uint8_t CC32xxEEPROMEmulation::SECTOR_COUNT = 8;

extern "C" {
void eeprom_updated_notification();
}

CC32xxEEPROMEmulation::CC32xxEEPROMEmulation(
    const char *name, size_t file_size_bytes)
    : EEPROM(name, file_size_bytes)
{
    data_ = (uint8_t *)malloc(file_size_bytes);
    HASSERT(data_);
    memset(data_, 0xff, file_size_bytes);
}

void CC32xxEEPROMEmulation::mount()
{
    bool have_rot = false;
    // First we need to find what was the last written segment.
    for (unsigned sector = 0; sector < SECTOR_COUNT; ++sector)
    {
        int handle = open_file(sector, FS_MODE_OPEN_READ, true);
        if (handle < 0)
        {
            LOG(VERBOSE, "EEPROM: sector %u: could not open.", sector);
            continue;
        }
        unsigned b = 0xaa55aaaa;
        SlCheckResult(sl_FsRead(handle, 0, (uint8_t *)&b, 4), 4);
        sl_FsClose(handle, nullptr, nullptr, 0);
        LOG(VERBOSE, "EEPROM: sector %u: version %u.", sector, b);
        if (b >= fileVersion_)
        {
            readSector_ = sector;
            fileVersion_ = b;
            have_rot = true;
        }
    }

    if (have_rot)
    {
        LOG(VERBOSE, "EEPROM: read sector %u:", readSector_);
        int handle = open_file(readSector_, FS_MODE_OPEN_READ);
        int ret = sl_FsRead(handle, 4, data_, file_size());
        if (ret < 0)
        {
            SlCheckResult(ret);
        }
        SlCheckResult(sl_FsClose(handle, nullptr, nullptr, 0));
    } else {
        LOG(VERBOSE, "EEPROM: no read sector");
    }
}

CC32xxEEPROMEmulation::~CC32xxEEPROMEmulation()
{
    flush();
    free(data_);
}

void CC32xxEEPROMEmulation::flush_buffers()
{
    if (!isDirty_)
        return;
    ++fileVersion_;
    ++readSector_;
    if (readSector_ >= SECTOR_COUNT)
        readSector_ = 0;
    LOG(VERBOSE, "EEPROM: write sector %u version %u", readSector_, fileVersion_);
    int handle = open_file(readSector_, FS_MODE_OPEN_WRITE, true);
    if (handle < 0)
    {
        handle =
            open_file(readSector_, FS_MODE_OPEN_CREATE(file_size() + 4, 0));
    }
    SlCheckResult(sl_FsWrite(handle, 0, (uint8_t *)&fileVersion_, 4), 4);
    SlCheckResult(sl_FsWrite(handle, 4, data_, file_size()), file_size());
    SlCheckResult(sl_FsClose(handle, nullptr, nullptr, 0));
    isDirty_ = 0;
}

int CC32xxEEPROMEmulation::open_file(
    unsigned sector, uint32_t open_mode, bool ignore_error)
{
    string filename(name);
    filename.push_back('.');
    filename.push_back('0' + sector);
    int32_t handle = -1;
    int ret = sl_FsOpen((uint8_t *)filename.c_str(), open_mode, NULL, &handle);
    if (!ignore_error)
    {
        SlCheckResult(ret);
        HASSERT(handle >= 0);
    }
    return handle;
}

void CC32xxEEPROMEmulation::write(
    unsigned int index, const void *buf, size_t len)
{
    // Boundary checks are performed by the EEPROM class.
    if (memcmp(data_ + index, buf, len) == 0) {
        return;
    }
    memcpy(data_ + index, buf, len);
    isDirty_ = 1;
    eeprom_updated_notification();
}

void CC32xxEEPROMEmulation::read(unsigned int index, void *buf, size_t len)
{
    // Boundary checks are performed by the EEPROM class.
    memcpy(buf, data_ + index, len);
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: chips/p9/procedures/hwp/io/p9_io_gcr.H $                      */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* EKB Project                                                            */
/*                                                                        */
/* COPYRIGHT 2015,2016                                                    */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file p9_io_gcr.H
/// @brief Register Access.
///----------------------------------------------------------------------------
/// *HWP HWP Owner   : Chris Steffen <cwsteffen@us.ibm.com>
/// *HWP FW Owner    : Jamie Knight <rjknight@us.ibm.com>
/// *HWP Team        : IO
/// *HWP Level       : 2
/// *HWP Consumed by : FSP:HB
///----------------------------------------------------------------------------
///
/// @verbatim
/// Register Access via scom.
///
/// @endverbatim
///----------------------------------------------------------------------------

#ifndef P9_IO_GCR_H_
#define P9_IO_GCR_H_

//* *****************************
//* Defines
//* *****************************

// @brief IO Base Addresses
#define P9_PSI_PHY_BASE_0x00000000       0x00000000
#define P9_XBUS_PHY_BASE_0x06010C3F      0x06010C3F
#define P9_ABUS0_PHY_BASE_0x0901103F     0x0901103F
#define P9_ABUS3_PHY_BASE_0x0C01103F     0x0C01103F
#define P9_NVBUS0_PHY_BASE_0x0901103F    0x0901103F
#define P9_NVBUS3_PHY_BASE_0x0C01103F    0x0C01103F
#define P9_NVBUS1_PHY_BASE_0x08010C7F    0x08010C7F
#define P9_DMI0_PHY_BASE_0x02011A3F      0x02011A3F
#define P9_DMI1_PHY_BASE_0x02011E3F      0x02011E3F
#define CEN_PHY_BASE_0x0201043F          0x0201043F

#define BROADCAST_GROUP 0xF
#define BROADCAST_LANE  0x1F
//-----------------------------------------------------------------------------
//  FAPI Includes
//-----------------------------------------------------------------------------
#include <fapi2.H>

/**
 * @class Register
 * This class provides a generic template for a register to read/write SCOMs.
 * @tparam[in] REG_ID Specific Register ID that matches Field IDs that belong to
 * that specific register.  Used with a static assert for compile time errors.
 * @tparam[in] SCOM_ADDR Upper 32bits of a 64bit scom register address.  If the reg
 * is a flat scom register, this is all 0's.  If the register is an I/O GCR reg,
 * this contains direction, R/W, indirect address, etc.
 * @tparam[in] REG_WIDTH Size of the Register.  64 for flat scom register and 16 for
 * I/O GCR registers
 */
template < uint64_t REG_ID, uint64_t SCOM_ADDR, uint8_t REG_WIDTH>
class Register
{
    public:

        /**
         * @brief Class Constructor
         */
        Register() : _shadow(0) {};

        /**
         * @brief Class Destructor
         */
        ~Register(void) = default;

        /**
         * @brief SCOM read Function
         * @tparam[in] K fapi2::TargetType
         * @param[in]  i_target Target to operate on
         * @param[in]  i_group Group to operate on
         * @param[in]  i_lane Lane to operate on
         * @return return code. Zero on success, else platform specified error
         */
        template < fapi2::TargetType K >
        inline fapi2::ReturnCode read(const fapi2::Target < K > i_target,
                                      const uint8_t i_group = 0,
                                      const uint8_t i_lane = 0)
        {
            fapi2::buffer < uint64_t > data;
            uint64_t address = buildScomAddress(i_target, i_group, i_lane);
            FAPI_TRY( fapi2::getScom(i_target, address, data),
                      "getScom Failed(0x%X): Addr(0x%016llX) Data(0x%016llX)",
                      (uint64_t) fapi2::current_err, address, data);
            _shadow = data;
        fapi_try_exit:
            return fapi2::current_err;
        }

        /**
         * @brief SCOM write Function
         * @tparam[in] K fapi2::TargetType
         * @param[in]  i_target Target to operate on
         * @param[in]  i_group Group to operate on
         * @param[in]  i_lane Lane to operate on
         * @return return code. Zero on success, else platform specified error
         */
        template < fapi2::TargetType K >
        inline fapi2::ReturnCode write(const fapi2::Target < K > i_target,
                                       const uint8_t i_group = 0,
                                       const uint8_t i_lane = 0)
        {
            fapi2::buffer < uint64_t > data(_shadow);
            uint64_t address = buildScomAddress(i_target, i_group, i_lane);
            FAPI_TRY( fapi2::putScom(i_target, address, data),
                      "putScom Failed(0x%X): Addr(0x%016llX) Data(0x%016llX)",
                      (uint64_t) fapi2::current_err, address, data);
        fapi_try_exit:
            return fapi2::current_err;
        }

        /**
         * @brief Gets field data from the register data
         * @tparam[in] FIELD_ID Corresponds with the REG_ID to provide a compile
         * time error if the field does not below to the register
         * @tparam[in] START Represents the start bit of the field within the reg
         * @tparam[in] WIDTH Represents the width of the field within the reg
         * @return Field Data
         */
        template<uint64_t FIELD_ID, uint8_t START, uint8_t WIDTH>
        inline uint16_t get()
        {
            static_assert(FIELD_ID == REG_ID, "Field does not belong to Register");
            const uint8_t shift = REG_WIDTH - START - WIDTH;
            const uint64_t mask = ( (0x1 << WIDTH) - 1) << shift;
            return ((_shadow & mask) >> shift);
        }

        /**
         * @brief Sets the register data from the passed in field data
         * @tparam[in] FIELD_ID Corresponds with the REG_ID to provide a compile
         * time error if the field does not below to the register
         * @tparam[in] START Represents the start bit of the field within the reg
         * @tparam[in] WIDTH Represents the width of the field within the reg
         * @return void
         */
        template<uint64_t FIELD_ID, uint8_t START, uint8_t WIDTH>
        inline void set(const uint16_t i_data)
        {
            static_assert(FIELD_ID == REG_ID, "Field does not belong to Register");
            const uint8_t shift = REG_WIDTH - START - WIDTH;
            const uint64_t mask = ( (0x1 << WIDTH) - 1) << shift;
            set((_shadow & ~mask) | ((i_data << shift) & mask));
            return;
        }

        /**
         * @brief Gets field data from the register data.  Method to override
         * which data is recorded
         * @tparam[in] START Represents the start bit of the field within the reg
         * @tparam[in] WIDTH Represents the width of the field within the reg
         * @return Field Data
         */
        template<uint8_t START, uint8_t WIDTH>
        inline uint16_t get()
        {
            const uint8_t shift = REG_WIDTH - START - WIDTH;
            const uint64_t mask = ( (0x1 << WIDTH) - 1) << shift;
            return ((_shadow & mask) >> shift);
        }

        /**
         * @brief Sets the register data from the passed in field data.  Method
         * to override which data is recorded.
         * @tparam[in] START Represents the start bit of the field within the reg
         * @tparam[in] WIDTH Represents the width of the field within the reg
         * @param[in] i_data Data to be set to shadow register
         * @return void
         */
        template<uint8_t START, uint8_t WIDTH>
        inline void set(const uint16_t i_data)
        {
            const uint8_t shift = REG_WIDTH - START - WIDTH;
            const uint64_t mask = ( (0x1 << WIDTH) - 1) << shift;
            set((_shadow & ~mask) | ((i_data << shift) & mask));
            return;
        }

        /**
         * @brief Gets the register data
         * @return Register Data
         */
        inline uint64_t get() const
        {
            return _shadow;
        }

        /**
         * @brief Sets the register data
         * @param[in] i_data Data to be set to shadow register
         * @return void
         */
        inline void set(const uint64_t i_data)
        {
            _shadow = i_data;
            return;
        }

    private:

        /**
         * @brief Stores the Register read/write data for scoms
         */
        uint64_t _shadow;

        /**
         * @brief Builds the base scom address, group, and lane into the full
         *   scom address
         * @tparam[in] K fapi2::TargetType
         * @param[in] i_target FAPI2 Target
         * @param[in] i_group Group encoded into the scom address
         * @param[in] i_lane Lane encoded into the scom address
         * @return Full 64bit encoded scom address
         */
        template < fapi2::TargetType K >
        inline uint64_t buildScomAddress(const fapi2::Target < K > i_target,
                                         const uint8_t i_group,
                                         const uint8_t i_lane)
        {
            const uint8_t ADDRESS_SIZE = 64;
            const uint8_t GROUP_SHIFT  = ADDRESS_SIZE - 22 - 5;
            const uint8_t LANE_SHIFT   = ADDRESS_SIZE - 27 - 5;
            uint64_t address = SCOM_ADDR | getBaseAddress(i_target);

            // If information is > 0x3F, then the register must be a GCR indirect
            // access register.
            if(SCOM_ADDR > 0x3F)
            {
                address |= (uint64_t) i_group << GROUP_SHIFT; // Set Group
                address |= (uint64_t) i_lane << LANE_SHIFT; // Set Lane
            }
            // Flat Scom Register, the first 6 bits are unique.
            else
            {
                address = (address & 0xFFFFFFC0) | (SCOM_ADDR & 0x0000003F);
            }

            return address;
        }

        /**
         * @brief Builds the base scom address
         * @tparam[in] K fapi2::TargetType
         * @param[in] i_target FAPI2 Target
         * @return 32bit encoded base scom address
         */
        template < fapi2::TargetType K >
        inline uint32_t getBaseAddress(const fapi2::Target <K> i_target)
        {
            if(i_target.getType() == fapi2::TargetType::TARGET_TYPE_XBUS)
            {
                return P9_XBUS_PHY_BASE_0x06010C3F;
            }
            else if(i_target.getType() == fapi2::TargetType::TARGET_TYPE_ABUS)
            {
                return P9_ABUS0_PHY_BASE_0x0901103F;
            }
            else if(i_target.getType() == fapi2::TargetType::TARGET_TYPE_MCS)
            {
                return P9_DMI0_PHY_BASE_0x02011A3F;
            }
            else if(i_target.getType() == fapi2::TargetType::TARGET_TYPE_MEMBUF_CHIP)
            {
                return CEN_PHY_BASE_0x0201043F;
            }
            else
            {
                fapi2::IO_GCR_TARGET_TYPE_NOT_FOUND().set_TARGET(i_target).execute();
                FAPI_ERR("TargetType not found(0x%X)", i_target.getType());
            }

            return 0x0;
        }

};

#endif /* P9_IO_GCR_H_ */
<commit_msg>Fix compiler warning/error for p9_io_gcr.H<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: chips/p9/procedures/hwp/io/p9_io_gcr.H $                      */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* EKB Project                                                            */
/*                                                                        */
/* COPYRIGHT 2015,2016                                                    */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file p9_io_gcr.H
/// @brief Register Access.
///----------------------------------------------------------------------------
/// *HWP HWP Owner   : Chris Steffen <cwsteffen@us.ibm.com>
/// *HWP FW Owner    : Jamie Knight <rjknight@us.ibm.com>
/// *HWP Team        : IO
/// *HWP Level       : 2
/// *HWP Consumed by : FSP:HB
///----------------------------------------------------------------------------
///
/// @verbatim
/// Register Access via scom.
///
/// @endverbatim
///----------------------------------------------------------------------------

#ifndef P9_IO_GCR_H_
#define P9_IO_GCR_H_

//* *****************************
//* Defines
//* *****************************

// @brief IO Base Addresses
#define P9_PSI_PHY_BASE_0x00000000       0x00000000
#define P9_XBUS_PHY_BASE_0x06010C3F      0x06010C3F
#define P9_ABUS0_PHY_BASE_0x0901103F     0x0901103F
#define P9_ABUS3_PHY_BASE_0x0C01103F     0x0C01103F
#define P9_NVBUS0_PHY_BASE_0x0901103F    0x0901103F
#define P9_NVBUS3_PHY_BASE_0x0C01103F    0x0C01103F
#define P9_NVBUS1_PHY_BASE_0x08010C7F    0x08010C7F
#define P9_DMI0_PHY_BASE_0x02011A3F      0x02011A3F
#define P9_DMI1_PHY_BASE_0x02011E3F      0x02011E3F
#define CEN_PHY_BASE_0x0201043F          0x0201043F

#define BROADCAST_GROUP 0xF
#define BROADCAST_LANE  0x1F
//-----------------------------------------------------------------------------
//  FAPI Includes
//-----------------------------------------------------------------------------
#include <fapi2.H>

/**
 * @class Register
 * This class provides a generic template for a register to read/write SCOMs.
 * @tparam[in] REG_ID Specific Register ID that matches Field IDs that belong to
 * that specific register.  Used with a static assert for compile time errors.
 * @tparam[in] SCOM_ADDR Upper 32bits of a 64bit scom register address.  If the reg
 * is a flat scom register, this is all 0's.  If the register is an I/O GCR reg,
 * this contains direction, R/W, indirect address, etc.
 * @tparam[in] REG_WIDTH Size of the Register.  64 for flat scom register and 16 for
 * I/O GCR registers
 */
template < uint64_t REG_ID, uint64_t SCOM_ADDR, uint8_t REG_WIDTH>
class Register
{
    public:

        /**
         * @brief Class Constructor
         */
        Register() : _shadow(0) {};

        /**
         * @brief Class Destructor
         */
        ~Register(void) = default;

        /**
         * @brief SCOM read Function
         * @tparam[in] K fapi2::TargetType
         * @param[in]  i_target Target to operate on
         * @param[in]  i_group Group to operate on
         * @param[in]  i_lane Lane to operate on
         * @return return code. Zero on success, else platform specified error
         */
        template < fapi2::TargetType K >
        inline fapi2::ReturnCode read(const fapi2::Target < K > i_target,
                                      const uint8_t i_group = 0,
                                      const uint8_t i_lane = 0)
        {
            fapi2::buffer < uint64_t > data;
            uint64_t address = buildScomAddress(i_target, i_group, i_lane);
            FAPI_TRY( fapi2::getScom(i_target, address, data),
                      "getScom Failed(0x%X): Addr(0x%016llX) Data(0x%016llX)",
                      (uint64_t) fapi2::current_err, address, data);
            _shadow = data;
        fapi_try_exit:
            return fapi2::current_err;
        }

        /**
         * @brief SCOM write Function
         * @tparam[in] K fapi2::TargetType
         * @param[in]  i_target Target to operate on
         * @param[in]  i_group Group to operate on
         * @param[in]  i_lane Lane to operate on
         * @return return code. Zero on success, else platform specified error
         */
        template < fapi2::TargetType K >
        inline fapi2::ReturnCode write(const fapi2::Target < K > i_target,
                                       const uint8_t i_group = 0,
                                       const uint8_t i_lane = 0)
        {
            fapi2::buffer < uint64_t > data(_shadow);
            uint64_t address = buildScomAddress(i_target, i_group, i_lane);
            FAPI_TRY( fapi2::putScom(i_target, address, data),
                      "putScom Failed(0x%X): Addr(0x%016llX) Data(0x%016llX)",
                      (uint64_t) fapi2::current_err, address, data);
        fapi_try_exit:
            return fapi2::current_err;
        }

        /**
         * @brief Gets field data from the register data
         * @tparam[in] FIELD_ID Corresponds with the REG_ID to provide a compile
         * time error if the field does not below to the register
         * @tparam[in] START Represents the start bit of the field within the reg
         * @tparam[in] WIDTH Represents the width of the field within the reg
         * @return Field Data
         */
        template<uint64_t FIELD_ID, uint8_t START, uint8_t WIDTH>
        inline uint16_t get()
        {
            static_assert(FIELD_ID == REG_ID, "Field does not belong to Register");
            const uint8_t shift = REG_WIDTH - START - WIDTH;
            const uint64_t mask = ( (0x1 << WIDTH) - 1) << shift;
            return ((_shadow & mask) >> shift);
        }

        /**
         * @brief Sets the register data from the passed in field data
         * @tparam[in] FIELD_ID Corresponds with the REG_ID to provide a compile
         * time error if the field does not below to the register
         * @tparam[in] START Represents the start bit of the field within the reg
         * @tparam[in] WIDTH Represents the width of the field within the reg
         * @return void
         */
        template<uint64_t FIELD_ID, uint8_t START, uint8_t WIDTH>
        inline void set(const uint16_t i_data)
        {
            static_assert(FIELD_ID == REG_ID, "Field does not belong to Register");
            uint8_t shift = REG_WIDTH - START - WIDTH;

            // Boundary check to avoid shifting off the edge compiler warning
            if ( (shift + WIDTH) < 64 )
            {
                const uint64_t mask = ((0x1 << WIDTH) - 1) << shift;
                set((_shadow & ~mask) | ((i_data << shift) & mask));
            }

            return;
        }

        /**
         * @brief Gets field data from the register data.  Method to override
         * which data is recorded
         * @tparam[in] START Represents the start bit of the field within the reg
         * @tparam[in] WIDTH Represents the width of the field within the reg
         * @return Field Data
         */
        template<uint8_t START, uint8_t WIDTH>
        inline uint16_t get()
        {
            const uint8_t shift = REG_WIDTH - START - WIDTH;
            const uint64_t mask = ( (0x1 << WIDTH) - 1) << shift;
            return ((_shadow & mask) >> shift);
        }

        /**
         * @brief Sets the register data from the passed in field data.  Method
         * to override which data is recorded.
         * @tparam[in] START Represents the start bit of the field within the reg
         * @tparam[in] WIDTH Represents the width of the field within the reg
         * @param[in] i_data Data to be set to shadow register
         * @return void
         */
        template<uint8_t START, uint8_t WIDTH>
        inline void set(const uint16_t i_data)
        {
            const uint8_t shift = REG_WIDTH - START - WIDTH;
            const uint64_t mask = ( (0x1 << WIDTH) - 1) << shift;
            set((_shadow & ~mask) | ((i_data << shift) & mask));
            return;
        }

        /**
         * @brief Gets the register data
         * @return Register Data
         */
        inline uint64_t get() const
        {
            return _shadow;
        }

        /**
         * @brief Sets the register data
         * @param[in] i_data Data to be set to shadow register
         * @return void
         */
        inline void set(const uint64_t i_data)
        {
            _shadow = i_data;
            return;
        }

    private:

        /**
         * @brief Stores the Register read/write data for scoms
         */
        uint64_t _shadow;

        /**
         * @brief Builds the base scom address, group, and lane into the full
         *   scom address
         * @tparam[in] K fapi2::TargetType
         * @param[in] i_target FAPI2 Target
         * @param[in] i_group Group encoded into the scom address
         * @param[in] i_lane Lane encoded into the scom address
         * @return Full 64bit encoded scom address
         */
        template < fapi2::TargetType K >
        inline uint64_t buildScomAddress(const fapi2::Target < K > i_target,
                                         const uint8_t i_group,
                                         const uint8_t i_lane)
        {
            const uint8_t ADDRESS_SIZE = 64;
            const uint8_t GROUP_SHIFT  = ADDRESS_SIZE - 22 - 5;
            const uint8_t LANE_SHIFT   = ADDRESS_SIZE - 27 - 5;
            uint64_t address = SCOM_ADDR | getBaseAddress(i_target);

            // If information is > 0x3F, then the register must be a GCR indirect
            // access register.
            if(SCOM_ADDR > 0x3F)
            {
                address |= (uint64_t) i_group << GROUP_SHIFT; // Set Group
                address |= (uint64_t) i_lane << LANE_SHIFT; // Set Lane
            }
            // Flat Scom Register, the first 6 bits are unique.
            else
            {
                address = (address & 0xFFFFFFC0) | (SCOM_ADDR & 0x0000003F);
            }

            return address;
        }

        /**
         * @brief Builds the base scom address
         * @tparam[in] K fapi2::TargetType
         * @param[in] i_target FAPI2 Target
         * @return 32bit encoded base scom address
         */
        template < fapi2::TargetType K >
        inline uint32_t getBaseAddress(const fapi2::Target <K> i_target)
        {
            if(i_target.getType() == fapi2::TargetType::TARGET_TYPE_XBUS)
            {
                return P9_XBUS_PHY_BASE_0x06010C3F;
            }
            else if(i_target.getType() == fapi2::TargetType::TARGET_TYPE_ABUS)
            {
                return P9_ABUS0_PHY_BASE_0x0901103F;
            }
            else if(i_target.getType() == fapi2::TargetType::TARGET_TYPE_MCS)
            {
                return P9_DMI0_PHY_BASE_0x02011A3F;
            }
            else if(i_target.getType() == fapi2::TargetType::TARGET_TYPE_MEMBUF_CHIP)
            {
                return CEN_PHY_BASE_0x0201043F;
            }
            else
            {
                fapi2::IO_GCR_TARGET_TYPE_NOT_FOUND().set_TARGET(i_target).execute();
                FAPI_ERR("TargetType not found(0x%X)", i_target.getType());
            }

            return 0x0;
        }

};

#endif /* P9_IO_GCR_H_ */
<|endoftext|>