LCOV - code coverage report
Current view: top level - clang/tools/extra/clangd - Context.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 0 17 0.0 %
Date: 2018-07-13 00:08:38 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===--- Context.h - Mechanism for passing implicit data --------*- C++-*-===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // Context for storing and retrieving implicit data. Useful for passing implicit
      11             : // parameters on a per-request basis.
      12             : //
      13             : //===----------------------------------------------------------------------===//
      14             : 
      15             : #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONTEXT_H_
      16             : #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONTEXT_H_
      17             : 
      18             : #include "llvm/ADT/STLExtras.h"
      19             : #include "llvm/Support/Compiler.h"
      20             : #include <memory>
      21             : #include <type_traits>
      22             : 
      23             : namespace clang {
      24             : namespace clangd {
      25             : 
      26             : /// Values in a Context are indexed by typed keys.
      27             : /// Key<T> serves two purposes:
      28             : ///   - it provides a lookup key for the context (each Key is unique),
      29             : ///   - it makes lookup type-safe: a Key<T> can only map to a T (or nothing).
      30             : ///
      31             : /// Example:
      32             : ///    Key<int> RequestID;
      33             : ///    Key<int> Version;
      34             : ///
      35             : ///    Context Ctx = Context::empty().derive(RequestID, 10).derive(Version, 3);
      36             : ///    assert(*Ctx.get(RequestID) == 10);
      37             : ///    assert(*Ctx.get(Version) == 3);
      38             : ///
      39             : /// Keys are typically used across multiple functions, so most of the time you
      40             : /// would want to make them static class members or global variables.
      41             : template <class Type> class Key {
      42             : public:
      43             :   static_assert(!std::is_reference<Type>::value,
      44             :                 "Reference arguments to Key<> are not allowed");
      45             : 
      46             :   constexpr Key() = default;
      47             : 
      48             :   Key(Key const &) = delete;
      49             :   Key &operator=(Key const &) = delete;
      50             :   Key(Key &&) = delete;
      51             :   Key &operator=(Key &&) = delete;
      52             : };
      53             : 
      54             : /// A context is an immutable container for per-request data that must be
      55             : /// propagated through layers that don't care about it. An example is a request
      56             : /// ID that we may want to use when logging.
      57             : ///
      58             : /// Conceptually, a context is a heterogeneous map<Key<T>, T>. Each key has
      59             : /// an associated value type, which allows the map to be typesafe.
      60             : ///
      61             : /// There is an "ambient" context for each thread, Context::current().
      62             : /// Most functions should read from this, and use WithContextValue or
      63             : /// WithContext to extend or replace the context within a block scope.
      64             : /// Only code dealing with threads and extension points should need to use
      65             : /// other Context objects.
      66             : ///
      67             : /// You can't add data to an existing context, instead you create a new
      68             : /// immutable context derived from it with extra data added. When you retrieve
      69             : /// data, the context will walk up the parent chain until the key is found.
      70           0 : class Context {
      71             : public:
      72             :   /// Returns an empty root context that contains no data.
      73             :   static Context empty();
      74             :   /// Returns the context for the current thread, creating it if needed.
      75             :   static const Context &current();
      76             :   // Sets the current() context to Replacement, and returns the old context.
      77             :   // Prefer to use WithContext or WithContextValue to do this safely.
      78             :   static Context swapCurrent(Context Replacement);
      79             : 
      80             : private:
      81             :   struct Data;
      82             :   Context(std::shared_ptr<const Data> DataPtr);
      83             : 
      84             : public:
      85             :   /// Same as Context::empty(), please use Context::empty() instead.
      86             :   /// Constructor is defined to workaround a bug in MSVC's version of STL.
      87             :   /// (arguments of std::future<> must be default-construcitble in MSVC).
      88             :   Context() = default;
      89             : 
      90             :   /// Copy operations for this class are deleted, use an explicit clone() method
      91             :   /// when you need a copy of the context instead.
      92             :   Context(Context const &) = delete;
      93             :   Context &operator=(const Context &) = delete;
      94             : 
      95             :   Context(Context &&) = default;
      96             :   Context &operator=(Context &&) = default;
      97             : 
      98             :   /// Get data stored for a typed \p Key. If values are not found
      99             :   /// \returns Pointer to the data associated with \p Key. If no data is
     100             :   /// specified for \p Key, return null.
     101             :   template <class Type> const Type *get(const Key<Type> &Key) const {
     102           0 :     for (const Data *DataPtr = this->DataPtr.get(); DataPtr != nullptr;
     103             :          DataPtr = DataPtr->Parent.get()) {
     104           0 :       if (DataPtr->KeyPtr == &Key)
     105           0 :         return static_cast<const Type *>(DataPtr->Value->getValuePtr());
     106             :     }
     107             :     return nullptr;
     108             :   }
     109             : 
     110             :   /// A helper to get a reference to a \p Key that must exist in the map.
     111             :   /// Must not be called for keys that are not in the map.
     112             :   template <class Type> const Type &getExisting(const Key<Type> &Key) const {
     113             :     auto Val = get(Key);
     114             :     assert(Val && "Key does not exist");
     115             :     return *Val;
     116             :   }
     117             : 
     118             :   /// Derives a child context
     119             :   /// It is safe to move or destroy a parent context after calling derive().
     120             :   /// The child will keep its parent alive, and its data remains accessible.
     121             :   template <class Type>
     122           0 :   Context derive(const Key<Type> &Key,
     123             :                  typename std::decay<Type>::type Value) const & {
     124             :     return Context(std::make_shared<Data>(Data{
     125             :         /*Parent=*/DataPtr, &Key,
     126             :         llvm::make_unique<TypedAnyStorage<typename std::decay<Type>::type>>(
     127           0 :             std::move(Value))}));
     128             :   }
     129             : 
     130             :   template <class Type>
     131             :   Context
     132           0 :   derive(const Key<Type> &Key,
     133             :          typename std::decay<Type>::type Value) && /* takes ownership */ {
     134             :     return Context(std::make_shared<Data>(Data{
     135             :         /*Parent=*/std::move(DataPtr), &Key,
     136             :         llvm::make_unique<TypedAnyStorage<typename std::decay<Type>::type>>(
     137           0 :             std::move(Value))}));
     138             :   }
     139             : 
     140             :   /// Derives a child context, using an anonymous key.
     141             :   /// Intended for objects stored only for their destructor's side-effect.
     142             :   template <class Type> Context derive(Type &&Value) const & {
     143             :     static Key<typename std::decay<Type>::type> Private;
     144             :     return derive(Private, std::forward<Type>(Value));
     145             :   }
     146             : 
     147             :   template <class Type> Context derive(Type &&Value) && {
     148             :     static Key<typename std::decay<Type>::type> Private;
     149             :     return std::move(*this).derive(Private, std::forward<Type>(Value));
     150             :   }
     151             : 
     152             :   /// Clone this context object.
     153             :   Context clone() const;
     154             : 
     155             : private:
     156             :   class AnyStorage {
     157             :   public:
     158             :     virtual ~AnyStorage() = default;
     159             :     virtual void *getValuePtr() = 0;
     160             :   };
     161             : 
     162           0 :   template <class T> class TypedAnyStorage : public Context::AnyStorage {
     163             :     static_assert(std::is_same<typename std::decay<T>::type, T>::value,
     164             :                   "Argument to TypedAnyStorage must be decayed");
     165             : 
     166             :   public:
     167           0 :     TypedAnyStorage(T &&Value) : Value(std::move(Value)) {}
     168             : 
     169           0 :     void *getValuePtr() override { return &Value; }
     170             : 
     171             :   private:
     172             :     T Value;
     173             :   };
     174             : 
     175           0 :   struct Data {
     176             :     // We need to make sure Parent outlives the Value, so the order of members
     177             :     // is important. We do that to allow classes stored in Context's child
     178             :     // layers to store references to the data in the parent layers.
     179             :     std::shared_ptr<const Data> Parent;
     180             :     const void *KeyPtr;
     181             :     std::unique_ptr<AnyStorage> Value;
     182             :   };
     183             : 
     184             :   std::shared_ptr<const Data> DataPtr;
     185             : };
     186             : 
     187             : /// WithContext replaces Context::current() with a provided scope.
     188             : /// When the WithContext is destroyed, the original scope is restored.
     189             : /// For extending the current context with new value, prefer WithContextValue.
     190             : class LLVM_NODISCARD WithContext {
     191             : public:
     192           0 :   WithContext(Context C) : Restore(Context::swapCurrent(std::move(C))) {}
     193           0 :   ~WithContext() { Context::swapCurrent(std::move(Restore)); }
     194             :   WithContext(const WithContext &) = delete;
     195             :   WithContext &operator=(const WithContext &) = delete;
     196             :   WithContext(WithContext &&) = delete;
     197             :   WithContext &operator=(WithContext &&) = delete;
     198             : 
     199             : private:
     200             :   Context Restore;
     201             : };
     202             : 
     203             : /// WithContextValue extends Context::current() with a single value.
     204             : /// When the WithContextValue is destroyed, the original scope is restored.
     205           0 : class LLVM_NODISCARD WithContextValue {
     206             : public:
     207             :   template <typename T>
     208           0 :   WithContextValue(const Key<T> &K, typename std::decay<T>::type V)
     209           0 :       : Restore(Context::current().derive(K, std::move(V))) {}
     210             : 
     211             :   // Anonymous values can be used for the destructor side-effect.
     212             :   template <typename T>
     213             :   WithContextValue(T &&V)
     214             :       : Restore(Context::current().derive(std::forward<T>(V))) {}
     215             : 
     216             : private:
     217             :   WithContext Restore;
     218             : };
     219             : 
     220             : } // namespace clangd
     221             : } // namespace clang
     222             : 
     223             : #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONTEXT_H_

Generated by: LCOV version 1.13