blob: fdee150b44f5c7d92ba1ccf0fc062c4887e65b8c [file] [log] [blame]
Feng Xiao6ef984a2014-11-10 17:34:54 -08001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// This header file defines an internal class that encapsulates internal message
32// metadata (Unknown-field set, Arena pointer, ...) and allows its
33// representation to be made more space-efficient via various optimizations.
34//
35// Note that this is distinct from google::protobuf::Metadata, which encapsulates
36// Descriptor and Reflection pointers.
37
38#ifndef GOOGLE_PROTOBUF_METADATA_H__
39#define GOOGLE_PROTOBUF_METADATA_H__
40
41#include <google/protobuf/stubs/common.h>
42#include <google/protobuf/arena.h>
43#include <google/protobuf/unknown_field_set.h>
44
45namespace google {
46namespace protobuf {
47namespace internal {
48
49// This is the representation for messages that support arena allocation. It
50// uses a tagged pointer to either store the Arena pointer, if there are no
51// unknown fields, or a pointer to a block of memory with both the Arena pointer
52// and the UnknownFieldSet, if there are unknown fields. This optimization
53// allows for "zero-overhead" storage of the Arena pointer, relative to the
54// above baseline implementation.
55//
56// The tagged pointer uses the LSB to disambiguate cases, and uses bit 0 == 0 to
57// indicate an arena pointer and bit 0 == 1 to indicate a UFS+Arena-container
58// pointer.
Jisi Liu3b3c8ab2016-03-30 11:39:59 -070059class LIBPROTOBUF_EXPORT InternalMetadataWithArena {
Feng Xiao6ef984a2014-11-10 17:34:54 -080060 public:
61 InternalMetadataWithArena() : ptr_(NULL) {}
62 explicit InternalMetadataWithArena(Arena* arena)
63 : ptr_ (arena) {}
64
65 ~InternalMetadataWithArena() {
66 if (have_unknown_fields() && arena() == NULL) {
67 delete PtrValue<Container>();
68 }
69 ptr_ = NULL;
70 }
71
Feng Xiaoeee38b02015-08-22 18:25:48 -070072 GOOGLE_ATTRIBUTE_ALWAYS_INLINE const UnknownFieldSet& unknown_fields() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -080073 if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) {
74 return PtrValue<Container>()->unknown_fields_;
75 } else {
76 return *UnknownFieldSet::default_instance();
77 }
78 }
79
Feng Xiaoeee38b02015-08-22 18:25:48 -070080 GOOGLE_ATTRIBUTE_ALWAYS_INLINE UnknownFieldSet* mutable_unknown_fields() {
Feng Xiao6ef984a2014-11-10 17:34:54 -080081 if (GOOGLE_PREDICT_TRUE(have_unknown_fields())) {
82 return &PtrValue<Container>()->unknown_fields_;
83 } else {
84 return mutable_unknown_fields_slow();
85 }
86 }
87
Feng Xiaoeee38b02015-08-22 18:25:48 -070088 GOOGLE_ATTRIBUTE_ALWAYS_INLINE Arena* arena() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -080089 if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) {
90 return PtrValue<Container>()->arena_;
91 } else {
92 return PtrValue<Arena>();
93 }
94 }
95
Feng Xiaoeee38b02015-08-22 18:25:48 -070096 GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool have_unknown_fields() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -080097 return PtrTag() == kTagContainer;
98 }
99
Feng Xiaoeee38b02015-08-22 18:25:48 -0700100 GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(InternalMetadataWithArena* other) {
Feng Xiao6ef984a2014-11-10 17:34:54 -0800101 // Semantics here are that we swap only the unknown fields, not the arena
102 // pointer. We cannot simply swap ptr_ with other->ptr_ because we need to
103 // maintain our own arena ptr. Also, our ptr_ and other's ptr_ may be in
104 // different states (direct arena pointer vs. container with UFS) so we
105 // cannot simply swap ptr_ and then restore the arena pointers. We reuse
106 // UFS's swap implementation instead.
107 if (have_unknown_fields() || other->have_unknown_fields()) {
108 mutable_unknown_fields()->Swap(other->mutable_unknown_fields());
109 }
110 }
111
Feng Xiaoeee38b02015-08-22 18:25:48 -0700112 GOOGLE_ATTRIBUTE_ALWAYS_INLINE void* raw_arena_ptr() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -0800113 return ptr_;
114 }
115
116 private:
117 void* ptr_;
118
119 // Tagged pointer implementation.
120 enum {
121 // ptr_ is an Arena*.
122 kTagArena = 0,
123 // ptr_ is a Container*.
124 kTagContainer = 1,
125 };
126 static const intptr_t kPtrTagMask = 1;
127 static const intptr_t kPtrValueMask = ~kPtrTagMask;
128
129 // Accessors for pointer tag and pointer value.
Feng Xiaoeee38b02015-08-22 18:25:48 -0700130 GOOGLE_ATTRIBUTE_ALWAYS_INLINE int PtrTag() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -0800131 return reinterpret_cast<intptr_t>(ptr_) & kPtrTagMask;
132 }
133
134 template<typename T> T* PtrValue() const {
135 return reinterpret_cast<T*>(
136 reinterpret_cast<intptr_t>(ptr_) & kPtrValueMask);
137 }
138
139 // If ptr_'s tag is kTagContainer, it points to an instance of this struct.
140 struct Container {
141 UnknownFieldSet unknown_fields_;
142 Arena* arena_;
143 };
144
Feng Xiaoeee38b02015-08-22 18:25:48 -0700145 GOOGLE_ATTRIBUTE_NOINLINE UnknownFieldSet* mutable_unknown_fields_slow() {
Feng Xiao6ef984a2014-11-10 17:34:54 -0800146 Arena* my_arena = arena();
147 Container* container = Arena::Create<Container>(my_arena);
148 ptr_ = reinterpret_cast<void*>(
149 reinterpret_cast<intptr_t>(container) | kTagContainer);
150 container->arena_ = my_arena;
151 return &(container->unknown_fields_);
152 }
153};
154
155// Temporary compatibility typedef. Remove once this is released in components
156// and upb CL is submitted.
157typedef InternalMetadataWithArena InternalMetadata;
158
159} // namespace internal
160} // namespace protobuf
161
162} // namespace google
163#endif // GOOGLE_PROTOBUF_METADATA_H__