-
Notifications
You must be signed in to change notification settings - Fork 16.1k
Expand file tree
/
Copy pathfield_with_arena.h
More file actions
110 lines (90 loc) · 4.02 KB
/
field_with_arena.h
File metadata and controls
110 lines (90 loc) · 4.02 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
#ifndef GOOGLE_PROTOBUF_FIELD_WITH_ARENA_H__
#define GOOGLE_PROTOBUF_FIELD_WITH_ARENA_H__
#include <cstddef>
#include "absl/log/absl_check.h"
#include "google/protobuf/arena.h"
#include "google/protobuf/internal_metadata_locator.h"
#include "google/protobuf/internal_visibility.h"
#include "google/protobuf/metadata_lite.h"
// Must be included last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
namespace internal {
// A container that holds a `T` and an arena pointer, where `T` has an
// `InternalMetadataResolver` member. This is used for both directly
// arena-allocated `T`'s and split `T`'s. Both cases need to return the correct
// thing when a user calls `GetArena()` on `T`, or when internal code needs the
// arena to do memory allocation.
//
// This class is used to store `InternalMetadata` alongside `T` with an
// `InternalMetadataResolver`, since `InternalMetadataResolver`s can only point
// to an existing arena pointer "nearby" in memory.
//
// Note that `FieldWithArena<T>` is destructor-skippable if and only if `T` is
// destructor-skippable.
template <typename T>
class FieldWithArena : public ContainerDestructorSkippableBase<T> {
public:
using InternalArenaConstructable_ = void;
constexpr FieldWithArena() : field_() {}
template <typename... Args>
explicit FieldWithArena(Arena* arena, Args&&... args)
: _internal_metadata_(arena) {
StaticallyVerifyLayout();
// Construct `T` after setting `_internal_metadata_` so that `T` can safely
// call ResolveArena().
new (&field_) T(BuildOffset(), std::forward<Args>(args)...);
}
~FieldWithArena() {
// The destructor of `FieldWithArena` for destructor-skippable types must
// only be called if the field is not allocated on an arena.
if constexpr (Arena::is_destructor_skippable<T>::value) {
ABSL_DCHECK_EQ(GetArena(), nullptr);
}
field_.~T();
}
const T& field() const { return field_; }
T& field() { return field_; }
// Returns the arena that the field is allocated on. This is cheaper than
// calling `field().GetArena()`.
Arena* GetArena() const { return _internal_metadata_.arena(); }
private:
friend InternalMetadataOffset;
static constexpr InternalMetadataOffset BuildOffset();
// A method to statically verify the offset of `field_storage_`. We need to
// define this in a member function out of line because `FieldWithArena` needs
// to be fully defined to call `offsetof`, but `field_storage_` is private.
static constexpr void StaticallyVerifyLayout();
// Generated code sometimes doesn't have a complete type for `T` (for example,
// split repeated message fields). When the constructor of `FieldWithArena` is
// invoked, both the constructor and destructor of all members are pulled in.
// By placing the field in a union, we manually invoke its destructor and can
// prevent it from being pulled in except in the `Destroy()` method.
union {
T field_;
};
// Note that the name of this field must be `_internal_metadata_`, as
// `InternalMetadataOffset` expects a field with this name.
const InternalMetadata _internal_metadata_;
};
template <typename T>
constexpr InternalMetadataOffset FieldWithArena<T>::BuildOffset() {
return InternalMetadataOffset::Build<FieldWithArena,
offsetof(FieldWithArena, field_)>();
}
template <typename Element>
constexpr void FieldWithArena<Element>::StaticallyVerifyLayout() {
static_assert(
offsetof(FieldWithArena, field_) == 0,
"field_ must be at offset 0 in FieldWithArena. There are multiple places "
"throughout the code (e.g. reflection, VerifyHasBitConsistency) which "
"assume that you can find the wrapped field by interpreting a pointer as "
"the wrapped field type, and aren't aware of this wrapper class. By "
"placing `field_` at offset 0 in this struct, this assumption holds.");
}
} // namespace internal
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_FIELD_WITH_ARENA_H__