1 // 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 #include <google/protobuf/arenastring.h>
32
33 #include <google/protobuf/stubs/logging.h>
34 #include <google/protobuf/stubs/common.h>
35 #include <google/protobuf/parse_context.h>
36 #include <google/protobuf/io/coded_stream.h>
37 #include <google/protobuf/message_lite.h>
38 #include <google/protobuf/stubs/mutex.h>
39 #include <google/protobuf/stubs/strutil.h>
40 #include <google/protobuf/stubs/stl_util.h>
41
42 // clang-format off
43 #include <google/protobuf/port_def.inc>
44 // clang-format on
45
46 namespace google {
47 namespace protobuf {
48 namespace internal {
49
Init() const50 const std::string& LazyString::Init() const {
51 static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED};
52 mu.Lock();
53 const std::string* res = inited_.load(std::memory_order_acquire);
54 if (res == nullptr) {
55 auto init_value = init_value_;
56 res = ::new (static_cast<void*>(string_buf_))
57 std::string(init_value.ptr, init_value.size);
58 inited_.store(res, std::memory_order_release);
59 }
60 mu.Unlock();
61 return *res;
62 }
63
64
Set(const std::string * default_value,ConstStringParam value,::google::protobuf::Arena * arena)65 void ArenaStringPtr::Set(const std::string* default_value,
66 ConstStringParam value, ::google::protobuf::Arena* arena) {
67 if (IsDefault(default_value)) {
68 tagged_ptr_.Set(Arena::Create<std::string>(arena, value));
69 } else {
70 UnsafeMutablePointer()->assign(value.data(), value.length());
71 }
72 }
73
Set(const std::string * default_value,std::string && value,::google::protobuf::Arena * arena)74 void ArenaStringPtr::Set(const std::string* default_value, std::string&& value,
75 ::google::protobuf::Arena* arena) {
76 if (IsDefault(default_value)) {
77 if (arena == nullptr) {
78 tagged_ptr_.Set(new std::string(std::move(value)));
79 } else {
80 tagged_ptr_.Set(Arena::Create<std::string>(arena, std::move(value)));
81 }
82 } else if (IsDonatedString()) {
83 std::string* current = tagged_ptr_.Get();
84 auto* s = new (current) std::string(std::move(value));
85 arena->OwnDestructor(s);
86 tagged_ptr_.Set(s);
87 } else /* !IsDonatedString() */ {
88 *UnsafeMutablePointer() = std::move(value);
89 }
90 }
91
Set(EmptyDefault,ConstStringParam value,::google::protobuf::Arena * arena)92 void ArenaStringPtr::Set(EmptyDefault, ConstStringParam value,
93 ::google::protobuf::Arena* arena) {
94 Set(&GetEmptyStringAlreadyInited(), value, arena);
95 }
96
Set(EmptyDefault,std::string && value,::google::protobuf::Arena * arena)97 void ArenaStringPtr::Set(EmptyDefault, std::string&& value,
98 ::google::protobuf::Arena* arena) {
99 Set(&GetEmptyStringAlreadyInited(), std::move(value), arena);
100 }
101
Set(NonEmptyDefault,ConstStringParam value,::google::protobuf::Arena * arena)102 void ArenaStringPtr::Set(NonEmptyDefault, ConstStringParam value,
103 ::google::protobuf::Arena* arena) {
104 Set(nullptr, value, arena);
105 }
106
Set(NonEmptyDefault,std::string && value,::google::protobuf::Arena * arena)107 void ArenaStringPtr::Set(NonEmptyDefault, std::string&& value,
108 ::google::protobuf::Arena* arena) {
109 Set(nullptr, std::move(value), arena);
110 }
111
Mutable(EmptyDefault,::google::protobuf::Arena * arena)112 std::string* ArenaStringPtr::Mutable(EmptyDefault, ::google::protobuf::Arena* arena) {
113 if (!IsDonatedString() && !IsDefault(&GetEmptyStringAlreadyInited())) {
114 return UnsafeMutablePointer();
115 } else {
116 return MutableSlow(arena);
117 }
118 }
119
Mutable(const LazyString & default_value,::google::protobuf::Arena * arena)120 std::string* ArenaStringPtr::Mutable(const LazyString& default_value,
121 ::google::protobuf::Arena* arena) {
122 if (!IsDonatedString() && !IsDefault(nullptr)) {
123 return UnsafeMutablePointer();
124 } else {
125 return MutableSlow(arena, default_value);
126 }
127 }
128
MutableNoCopy(const std::string * default_value,::google::protobuf::Arena * arena)129 std::string* ArenaStringPtr::MutableNoCopy(const std::string* default_value,
130 ::google::protobuf::Arena* arena) {
131 if (!IsDonatedString() && !IsDefault(default_value)) {
132 return UnsafeMutablePointer();
133 } else {
134 GOOGLE_DCHECK(IsDefault(default_value));
135 // Allocate empty. The contents are not relevant.
136 std::string* new_string = Arena::Create<std::string>(arena);
137 tagged_ptr_.Set(new_string);
138 return new_string;
139 }
140 }
141
142 template <typename... Lazy>
MutableSlow(::google::protobuf::Arena * arena,const Lazy &...lazy_default)143 std::string* ArenaStringPtr::MutableSlow(::google::protobuf::Arena* arena,
144 const Lazy&... lazy_default) {
145 const std::string* const default_value =
146 sizeof...(Lazy) == 0 ? &GetEmptyStringAlreadyInited() : nullptr;
147 GOOGLE_DCHECK(IsDefault(default_value));
148 std::string* new_string =
149 Arena::Create<std::string>(arena, lazy_default.get()...);
150 tagged_ptr_.Set(new_string);
151 return new_string;
152 }
153
Release(const std::string * default_value,::google::protobuf::Arena * arena)154 std::string* ArenaStringPtr::Release(const std::string* default_value,
155 ::google::protobuf::Arena* arena) {
156 if (IsDefault(default_value)) {
157 return nullptr;
158 } else {
159 return ReleaseNonDefault(default_value, arena);
160 }
161 }
162
ReleaseNonDefault(const std::string * default_value,::google::protobuf::Arena * arena)163 std::string* ArenaStringPtr::ReleaseNonDefault(const std::string* default_value,
164 ::google::protobuf::Arena* arena) {
165 GOOGLE_DCHECK(!IsDefault(default_value));
166
167 if (!IsDonatedString()) {
168 std::string* released;
169 if (arena != nullptr) {
170 released = new std::string;
171 released->swap(*UnsafeMutablePointer());
172 } else {
173 released = UnsafeMutablePointer();
174 }
175 tagged_ptr_.Set(const_cast<std::string*>(default_value));
176 return released;
177 } else /* IsDonatedString() */ {
178 GOOGLE_DCHECK(arena != nullptr);
179 std::string* released = new std::string(Get());
180 tagged_ptr_.Set(const_cast<std::string*>(default_value));
181 return released;
182 }
183 }
184
SetAllocated(const std::string * default_value,std::string * value,::google::protobuf::Arena * arena)185 void ArenaStringPtr::SetAllocated(const std::string* default_value,
186 std::string* value, ::google::protobuf::Arena* arena) {
187 // Release what we have first.
188 if (arena == nullptr && !IsDefault(default_value)) {
189 delete UnsafeMutablePointer();
190 }
191 if (value == nullptr) {
192 tagged_ptr_.Set(const_cast<std::string*>(default_value));
193 } else {
194 #ifdef NDEBUG
195 tagged_ptr_.Set(value);
196 if (arena != nullptr) {
197 arena->Own(value);
198 }
199 #else
200 // On debug builds, copy the string so the address differs. delete will
201 // fail if value was a stack-allocated temporary/etc., which would have
202 // failed when arena ran its cleanup list.
203 std::string* new_value = Arena::Create<std::string>(arena, *value);
204 delete value;
205 tagged_ptr_.Set(new_value);
206 #endif
207 }
208 }
209
Destroy(const std::string * default_value,::google::protobuf::Arena * arena)210 void ArenaStringPtr::Destroy(const std::string* default_value,
211 ::google::protobuf::Arena* arena) {
212 if (arena == nullptr) {
213 GOOGLE_DCHECK(!IsDonatedString());
214 if (!IsDefault(default_value)) {
215 delete UnsafeMutablePointer();
216 }
217 }
218 }
219
Destroy(EmptyDefault,::google::protobuf::Arena * arena)220 void ArenaStringPtr::Destroy(EmptyDefault, ::google::protobuf::Arena* arena) {
221 Destroy(&GetEmptyStringAlreadyInited(), arena);
222 }
223
Destroy(NonEmptyDefault,::google::protobuf::Arena * arena)224 void ArenaStringPtr::Destroy(NonEmptyDefault, ::google::protobuf::Arena* arena) {
225 Destroy(nullptr, arena);
226 }
227
ClearToEmpty()228 void ArenaStringPtr::ClearToEmpty() {
229 if (IsDefault(&GetEmptyStringAlreadyInited())) {
230 // Already set to default -- do nothing.
231 } else {
232 // Unconditionally mask away the tag.
233 //
234 // UpdateDonatedString uses assign when capacity is larger than the new
235 // value, which is trivially true in the donated string case.
236 // const_cast<std::string*>(PtrValue<std::string>())->clear();
237 tagged_ptr_.Get()->clear();
238 }
239 }
240
ClearToDefault(const LazyString & default_value,::google::protobuf::Arena * arena)241 void ArenaStringPtr::ClearToDefault(const LazyString& default_value,
242 ::google::protobuf::Arena* arena) {
243 (void)arena;
244 if (IsDefault(nullptr)) {
245 // Already set to default -- do nothing.
246 } else if (!IsDonatedString()) {
247 UnsafeMutablePointer()->assign(default_value.get());
248 }
249 }
250
251
252 } // namespace internal
253 } // namespace protobuf
254 } // namespace google
255