• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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