forked from nodejs/node
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontextual.h
More file actions
131 lines (108 loc) Β· 4.75 KB
/
contextual.h
File metadata and controls
131 lines (108 loc) Β· 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_BASE_CONTEXTUAL_H_
#define V8_BASE_CONTEXTUAL_H_
#include <type_traits>
#include "src/base/export-template.h"
#include "src/base/macros.h"
#include "src/base/platform/platform.h"
namespace v8::base {
// {ContextualVariable} provides a clean alternative to a global variable.
// The contextual variable is mutable, and supports managing the value of
// a variable in a well-nested fashion via the {Scope} class.
// {ContextualVariable} only stores a pointer to the current value, which
// is stored in a {Scope} object. The most recent value can be retrieved
// via Get(). Because only {Scope} has actual storage, there must be at
// least one active {Scope} (i.e. in a surrounding C++ scope), whenever Get()
// is called.
// Note that contextual variables must only be used from the same thread,
// i.e. {Scope} and Get() have to be in the same thread.
template <class Derived, class VarType>
class V8_EXPORT_PRIVATE ContextualVariable {
public:
using VarT = VarType;
// A {Scope} contains a new object of type {VarType} and gives
// ContextualVariable::Get() access to it. Upon destruction, the contextual
// variable is restored to the state before the {Scope} was created. Scopes
// have to follow a stack discipline: A {Scope} has to be destructed before
// any older scope is destructed.
class V8_NODISCARD Scope {
public:
template <class... Args>
explicit Scope(Args&&... args)
: value_(std::forward<Args>(args)...), previous_(Top()) {
Top() = this;
}
~Scope() {
// Ensure stack discipline.
DCHECK_EQ(this, Top());
Top() = previous_;
}
Scope(const Scope&) = delete;
Scope& operator=(const Scope&) = delete;
VarType& Value() { return value_; }
private:
VarType value_;
Scope* previous_;
static_assert(std::is_base_of<ContextualVariable, Derived>::value,
"Curiously Recurring Template Pattern");
DISALLOW_NEW_AND_DELETE()
};
static VarType& Get() {
DCHECK(HasScope());
return Top()->Value();
}
static bool HasScope() { return Top() != nullptr; }
private:
inline static thread_local Scope* top_ = nullptr;
#if defined(USING_V8_SHARED)
// Hide the access to `top_` from other DLLs/libraries, since access to
// thread_local variables from other DLLs/libraries does not work correctly.
static Scope*& Top() { return ExportedTop(); }
#else
static Scope*& Top() { return top_; }
#endif
// Same as `Top()`, but non-inline and exported to DLLs/libraries.
// If there is a linking error for `ExportedTop()`, then the contextual
// variable probably needs to be exported using EXPORT_CONTEXTUAL_VARIABLE.
static Scope*& ExportedTop();
};
// Usage: DECLARE_CONTEXTUAL_VARIABLE(VarName, VarType)
#define DECLARE_CONTEXTUAL_VARIABLE(VarName, ...) \
struct VarName : ::v8::base::ContextualVariable<VarName, __VA_ARGS__> {}
// Contextual variables that are accessed in tests need to be
// exported. For this, place the following macro in the global namespace inside
// of a .cc file.
#define EXPORT_CONTEXTUAL_VARIABLE(VarName) \
namespace v8::base { \
template <> \
V8_EXPORT_PRIVATE typename VarName::Scope*& \
ContextualVariable<VarName, typename VarName::VarT>::ExportedTop() { \
return top_; \
} \
}
// By inheriting from {ContextualClass} a class can become a contextual variable
// of itself, which is very similar to a singleton.
template <class T>
using ContextualClass = ContextualVariable<T, T>;
// {ContextualVariableWithDefault} is similar to a {ContextualVariable},
// with the difference that a default value is used if there is no active
// {Scope} object.
template <class Derived, class VarType, auto... default_args>
class V8_EXPORT_PRIVATE ContextualVariableWithDefault
: public ContextualVariable<Derived, VarType> {
public:
static VarType& Get() {
return Base::HasScope() ? Base::Get() : default_value_;
}
private:
using Base = ContextualVariable<Derived, VarType>;
inline static thread_local VarType default_value_{default_args...};
};
// Usage: DECLARE_CONTEXTUAL_VARIABLE_WITH_DEFAULT(VarName, VarType, Args...)
#define DECLARE_CONTEXTUAL_VARIABLE_WITH_DEFAULT(VarName, ...) \
struct VarName \
: ::v8::base::ContextualVariableWithDefault<VarName, __VA_ARGS__> {}
} // namespace v8::base
#endif // V8_BASE_CONTEXTUAL_H_