File: | .cache/bazel/_bazel_alan/39be661231df2a680c9b74265384c13c/execroot/org_tensorflow/tensorflow/python/util/util.cc |
Warning: | line 540, column 21 PyObject ownership leak with reference count of 1 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Copyright 2017 The TensorFlow Authors. All Rights Reserved. | ||||||||||
2 | |||||||||||
3 | Licensed under the Apache License, Version 2.0 (the "License"); | ||||||||||
4 | you may not use this file except in compliance with the License. | ||||||||||
5 | You may obtain a copy of the License at | ||||||||||
6 | |||||||||||
7 | http://www.apache.org/licenses/LICENSE-2.0 | ||||||||||
8 | |||||||||||
9 | Unless required by applicable law or agreed to in writing, software | ||||||||||
10 | distributed under the License is distributed on an "AS IS" BASIS, | ||||||||||
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||||||
12 | See the License for the specific language governing permissions and | ||||||||||
13 | limitations under the License. | ||||||||||
14 | ==============================================================================*/ | ||||||||||
15 | #include "tensorflow/python/util/util.h" | ||||||||||
16 | |||||||||||
17 | #include <functional> | ||||||||||
18 | #include <memory> | ||||||||||
19 | #include <unordered_map> | ||||||||||
20 | #include <vector> | ||||||||||
21 | |||||||||||
22 | #include "absl/memory/memory.h" | ||||||||||
23 | #include "tensorflow/core/lib/gtl/map_util.h" | ||||||||||
24 | #include "tensorflow/core/lib/strings/strcat.h" | ||||||||||
25 | #include "tensorflow/core/platform/logging.h" | ||||||||||
26 | #include "tensorflow/core/platform/mutex.h" | ||||||||||
27 | #include "tensorflow/python/lib/core/safe_pyobject_ptr.h" | ||||||||||
28 | |||||||||||
29 | namespace tensorflow { | ||||||||||
30 | namespace swig { | ||||||||||
31 | |||||||||||
32 | namespace { | ||||||||||
33 | string PyObjectToString(PyObject* o); | ||||||||||
34 | } // namespace | ||||||||||
35 | |||||||||||
36 | std::unordered_map<string, PyObject*>* RegisteredPyObjectMap() { | ||||||||||
37 | static auto* m = new std::unordered_map<string, PyObject*>(); | ||||||||||
38 | return m; | ||||||||||
39 | } | ||||||||||
40 | |||||||||||
41 | PyObject* GetRegisteredPyObject(const string& name) { | ||||||||||
42 | const auto* m = RegisteredPyObjectMap(); | ||||||||||
43 | auto it = m->find(name); | ||||||||||
44 | if (it == m->end()) { | ||||||||||
45 | PyErr_SetString(PyExc_TypeError, | ||||||||||
46 | tensorflow::strings::StrCat("No object with name ", name, | ||||||||||
47 | " has been registered.") | ||||||||||
48 | .c_str()); | ||||||||||
49 | return nullptr; | ||||||||||
50 | } | ||||||||||
51 | return it->second; | ||||||||||
52 | } | ||||||||||
53 | |||||||||||
54 | PyObject* RegisterType(PyObject* type_name, PyObject* type) { | ||||||||||
55 | if (!PyType_Check(type)((((((PyObject*)(type))->ob_type))->tp_flags & ((1UL << 31))) != 0)) { | ||||||||||
56 | PyErr_SetString(PyExc_TypeError, | ||||||||||
57 | tensorflow::strings::StrCat("Expecting a type, got ", | ||||||||||
58 | Py_TYPE(type)(((PyObject*)(type))->ob_type)->tp_name) | ||||||||||
59 | .c_str()); | ||||||||||
60 | return nullptr; | ||||||||||
61 | } | ||||||||||
62 | return RegisterPyObject(type_name, type); | ||||||||||
63 | } | ||||||||||
64 | |||||||||||
65 | PyObject* RegisterPyObject(PyObject* name, PyObject* value) { | ||||||||||
66 | string key; | ||||||||||
67 | if (PyBytes_Check(name)((((((PyObject*)(name))->ob_type))->tp_flags & ((1UL << 27))) != 0)) { | ||||||||||
68 | key = PyBytes_AsString(name); | ||||||||||
69 | #if PY_MAJOR_VERSION3 >= 3 | ||||||||||
70 | } else if (PyUnicode_Check(name)((((((PyObject*)(name))->ob_type))->tp_flags & ((1UL << 28))) != 0)) { | ||||||||||
71 | key = PyUnicode_AsUTF8(name); | ||||||||||
72 | #endif | ||||||||||
73 | } else { | ||||||||||
74 | PyErr_SetString(PyExc_TypeError, tensorflow::strings::StrCat( | ||||||||||
75 | "Expected name to be a str, got", | ||||||||||
76 | PyObjectToString(name)) | ||||||||||
77 | .c_str()); | ||||||||||
78 | return nullptr; | ||||||||||
79 | } | ||||||||||
80 | |||||||||||
81 | auto* m = RegisteredPyObjectMap(); | ||||||||||
82 | if (m->find(key) != m->end()) { | ||||||||||
83 | PyErr_SetString(PyExc_TypeError, tensorflow::strings::StrCat( | ||||||||||
84 | "Value already registered for ", key) | ||||||||||
85 | .c_str()); | ||||||||||
86 | return nullptr; | ||||||||||
87 | } | ||||||||||
88 | |||||||||||
89 | Py_INCREF(value)_Py_INCREF(((PyObject*)(value))); | ||||||||||
90 | m->emplace(key, value); | ||||||||||
91 | |||||||||||
92 | Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (& _Py_NoneStruct); | ||||||||||
93 | } | ||||||||||
94 | |||||||||||
95 | namespace { | ||||||||||
96 | const int kMaxItemsInCache = 1024; | ||||||||||
97 | |||||||||||
98 | bool WarnedThatSetIsNotSequence = false; | ||||||||||
99 | |||||||||||
100 | bool IsString(PyObject* o) { | ||||||||||
101 | return PyBytes_Check(o)((((((PyObject*)(o))->ob_type))->tp_flags & ((1UL << 27))) != 0) || | ||||||||||
102 | #if PY_MAJOR_VERSION3 < 3 | ||||||||||
103 | PyString_Check(o) || | ||||||||||
104 | #endif | ||||||||||
105 | PyUnicode_Check(o)((((((PyObject*)(o))->ob_type))->tp_flags & ((1UL << 28))) != 0); | ||||||||||
106 | } | ||||||||||
107 | |||||||||||
108 | // Equivalent to Python's 'o.__class__.__name__' | ||||||||||
109 | // Note that '__class__' attribute is set only in new-style classes. | ||||||||||
110 | // A lot of tensorflow code uses __class__ without checks, so it seems like | ||||||||||
111 | // we only support new-style classes. | ||||||||||
112 | StringPiece GetClassName(PyObject* o) { | ||||||||||
113 | // __class__ is equivalent to type() for new style classes. | ||||||||||
114 | // type() is equivalent to PyObject_Type() | ||||||||||
115 | // (https://docs.python.org/3.5/c-api/object.html#c.PyObject_Type) | ||||||||||
116 | // PyObject_Type() is equivalent to o->ob_type except for Py_INCREF, which | ||||||||||
117 | // we don't need here. | ||||||||||
118 | PyTypeObject* type = o->ob_type; | ||||||||||
119 | |||||||||||
120 | // __name__ is the value of `tp_name` after the last '.' | ||||||||||
121 | // (https://docs.python.org/2/c-api/typeobj.html#c.PyTypeObject.tp_name) | ||||||||||
122 | StringPiece name(type->tp_name); | ||||||||||
123 | size_t pos = name.rfind('.'); | ||||||||||
124 | if (pos != StringPiece::npos) { | ||||||||||
125 | name.remove_prefix(pos + 1); | ||||||||||
126 | } | ||||||||||
127 | return name; | ||||||||||
128 | } | ||||||||||
129 | |||||||||||
130 | string PyObjectToString(PyObject* o) { | ||||||||||
131 | if (o == nullptr) { | ||||||||||
132 | return "<null object>"; | ||||||||||
133 | } | ||||||||||
134 | PyObject* str = PyObject_Str(o); | ||||||||||
135 | if (str) { | ||||||||||
136 | #if PY_MAJOR_VERSION3 < 3 | ||||||||||
137 | string s(PyString_AS_STRING(str)); | ||||||||||
138 | #else | ||||||||||
139 | string s(PyUnicode_AsUTF8(str)); | ||||||||||
140 | #endif | ||||||||||
141 | Py_DECREF(str)_Py_DECREF(((PyObject*)(str))); | ||||||||||
142 | return tensorflow::strings::StrCat("type=", GetClassName(o), " str=", s); | ||||||||||
143 | } else { | ||||||||||
144 | return "<failed to execute str() on object>"; | ||||||||||
145 | } | ||||||||||
146 | } | ||||||||||
147 | |||||||||||
148 | class CachedTypeCheck { | ||||||||||
149 | public: | ||||||||||
150 | explicit CachedTypeCheck(std::function<int(PyObject*)> ternary_predicate) | ||||||||||
151 | : ternary_predicate_(std::move(ternary_predicate)) {} | ||||||||||
152 | |||||||||||
153 | ~CachedTypeCheck() { | ||||||||||
154 | mutex_lock l(type_to_sequence_map_mu_); | ||||||||||
155 | for (const auto& pair : type_to_sequence_map_) { | ||||||||||
156 | Py_DECREF(pair.first)_Py_DECREF(((PyObject*)(pair.first))); | ||||||||||
157 | } | ||||||||||
158 | } | ||||||||||
159 | |||||||||||
160 | // Caches successful executions of the one-argument (PyObject*) callable | ||||||||||
161 | // "ternary_predicate" based on the type of "o". -1 from the callable | ||||||||||
162 | // indicates an unsuccessful check (not cached), 0 indicates that "o"'s type | ||||||||||
163 | // does not match the predicate, and 1 indicates that it does. Used to avoid | ||||||||||
164 | // calling back into Python for expensive isinstance checks. | ||||||||||
165 | int CachedLookup(PyObject* o) { | ||||||||||
166 | // Try not to return to Python - see if the type has already been seen | ||||||||||
167 | // before. | ||||||||||
168 | |||||||||||
169 | auto* type = Py_TYPE(o)(((PyObject*)(o))->ob_type); | ||||||||||
170 | |||||||||||
171 | { | ||||||||||
172 | tf_shared_lock l(type_to_sequence_map_mu_); | ||||||||||
173 | auto it = type_to_sequence_map_.find(type); | ||||||||||
174 | if (it != type_to_sequence_map_.end()) { | ||||||||||
175 | return it->second; | ||||||||||
176 | } | ||||||||||
177 | } | ||||||||||
178 | |||||||||||
179 | int check_result = ternary_predicate_(o); | ||||||||||
180 | |||||||||||
181 | if (check_result == -1) { | ||||||||||
182 | return -1; // Type check error, not cached. | ||||||||||
183 | } | ||||||||||
184 | |||||||||||
185 | // NOTE: This is never decref'd as long as the object lives, which is likely | ||||||||||
186 | // forever, but we don't want the type to get deleted as long as it is in | ||||||||||
187 | // the map. This should not be too much of a leak, as there should only be a | ||||||||||
188 | // relatively small number of types in the map, and an even smaller number | ||||||||||
189 | // that are eligible for decref. As a precaution, we limit the size of the | ||||||||||
190 | // map to 1024. | ||||||||||
191 | { | ||||||||||
192 | mutex_lock l(type_to_sequence_map_mu_); | ||||||||||
193 | if (type_to_sequence_map_.size() < kMaxItemsInCache) { | ||||||||||
194 | Py_INCREF(type)_Py_INCREF(((PyObject*)(type))); | ||||||||||
195 | auto insert_result = type_to_sequence_map_.insert({type, check_result}); | ||||||||||
196 | if (!insert_result.second) { | ||||||||||
197 | // The type was added to the cache by a concurrent thread after we | ||||||||||
198 | // looked it up above. | ||||||||||
199 | Py_DECREF(type)_Py_DECREF(((PyObject*)(type))); | ||||||||||
200 | } | ||||||||||
201 | } | ||||||||||
202 | } | ||||||||||
203 | |||||||||||
204 | return check_result; | ||||||||||
205 | } | ||||||||||
206 | |||||||||||
207 | private: | ||||||||||
208 | std::function<int(PyObject*)> ternary_predicate_; | ||||||||||
209 | mutex type_to_sequence_map_mu_; | ||||||||||
210 | std::unordered_map<PyTypeObject*, bool> type_to_sequence_map_ | ||||||||||
211 | TF_GUARDED_BY(type_to_sequence_map_mu_)__attribute__((guarded_by(type_to_sequence_map_mu_))); | ||||||||||
212 | }; | ||||||||||
213 | |||||||||||
214 | // Returns 1 if 'obj' is an instance of 'type_name' | ||||||||||
215 | // Returns 0 otherwise. | ||||||||||
216 | // Returns -1 if an error occurred (e.g., if 'type_name' is not registered.) | ||||||||||
217 | int IsInstanceOfRegisteredType(PyObject* obj, const char* type_name) { | ||||||||||
218 | PyObject* type_obj = GetRegisteredPyObject(type_name); | ||||||||||
219 | if (TF_PREDICT_FALSE(type_obj == nullptr)(__builtin_expect(type_obj == nullptr, 0))) { | ||||||||||
220 | PyErr_SetString(PyExc_RuntimeError, | ||||||||||
221 | tensorflow::strings::StrCat( | ||||||||||
222 | type_name, | ||||||||||
223 | " type has not been set. " | ||||||||||
224 | "Please register the type with the identifier \"", | ||||||||||
225 | type_name, "\" using RegisterType.") | ||||||||||
226 | .c_str()); | ||||||||||
227 | return -1; | ||||||||||
228 | } | ||||||||||
229 | return PyObject_IsInstance(obj, type_obj); | ||||||||||
230 | } | ||||||||||
231 | |||||||||||
232 | // Returns 1 if `o` is considered a mapping for the purposes of Flatten(). | ||||||||||
233 | // Returns 0 otherwise. | ||||||||||
234 | // Returns -1 if an error occurred. | ||||||||||
235 | int IsMappingHelper(PyObject* o) { | ||||||||||
236 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
237 | return IsInstanceOfRegisteredType(to_check, "Mapping"); | ||||||||||
238 | }); | ||||||||||
239 | if (PyDict_Check(o)((((((PyObject*)(o))->ob_type))->tp_flags & ((1UL << 29))) != 0)) return true; | ||||||||||
240 | return check_cache->CachedLookup(o); | ||||||||||
241 | } | ||||||||||
242 | |||||||||||
243 | // Returns 1 if `o` is considered a mutable mapping for the purposes of | ||||||||||
244 | // Flatten(). Returns 0 otherwise. Returns -1 if an error occurred. | ||||||||||
245 | int IsMutableMappingHelper(PyObject* o) { | ||||||||||
246 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
247 | return IsInstanceOfRegisteredType(to_check, "MutableMapping"); | ||||||||||
248 | }); | ||||||||||
249 | if (PyDict_Check(o)((((((PyObject*)(o))->ob_type))->tp_flags & ((1UL << 29))) != 0)) return true; | ||||||||||
250 | return check_cache->CachedLookup(o); | ||||||||||
251 | } | ||||||||||
252 | |||||||||||
253 | // Returns 1 if `o` is considered a mapping view for the purposes of Flatten(). | ||||||||||
254 | // Returns 0 otherwise. | ||||||||||
255 | // Returns -1 if an error occurred. | ||||||||||
256 | int IsMappingViewHelper(PyObject* o) { | ||||||||||
257 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
258 | return IsInstanceOfRegisteredType(to_check, "MappingView"); | ||||||||||
259 | }); | ||||||||||
260 | return check_cache->CachedLookup(o); | ||||||||||
261 | } | ||||||||||
262 | |||||||||||
263 | // Returns 1 if `o` is considered an object proxy | ||||||||||
264 | // Returns 0 otherwise. | ||||||||||
265 | // Returns -1 if an error occurred. | ||||||||||
266 | int IsObjectProxy(PyObject* o) { | ||||||||||
267 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
268 | return IsInstanceOfRegisteredType(to_check, "ObjectProxy"); | ||||||||||
269 | }); | ||||||||||
270 | return check_cache->CachedLookup(o); | ||||||||||
271 | } | ||||||||||
272 | |||||||||||
273 | // Returns 1 if `o` is an instance of attrs-decorated class. | ||||||||||
274 | // Returns 0 otherwise. | ||||||||||
275 | int IsAttrsHelper(PyObject* o) { | ||||||||||
276 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
277 | Safe_PyObjectPtr cls(PyObject_GetAttrString(to_check, "__class__")); | ||||||||||
278 | if (cls) { | ||||||||||
279 | return PyObject_HasAttrString(cls.get(), "__attrs_attrs__"); | ||||||||||
280 | } | ||||||||||
281 | |||||||||||
282 | // PyObject_GetAttrString returns null on error | ||||||||||
283 | PyErr_Clear(); | ||||||||||
284 | return 0; | ||||||||||
285 | }); | ||||||||||
286 | return check_cache->CachedLookup(o); | ||||||||||
287 | } | ||||||||||
288 | |||||||||||
289 | // Returns 1 if `o` is an object of type IndexedSlices. | ||||||||||
290 | // Returns 0 otherwise. | ||||||||||
291 | // Returns -1 if an error occurred. | ||||||||||
292 | int IsIndexedSlicesHelper(PyObject* o) { | ||||||||||
293 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
294 | return IsInstanceOfRegisteredType(to_check, "IndexedSlices"); | ||||||||||
295 | }); | ||||||||||
296 | return check_cache->CachedLookup(o); | ||||||||||
297 | } | ||||||||||
298 | |||||||||||
299 | // Returns 1 if `o` is a Tensor. | ||||||||||
300 | // Returns 0 otherwise. | ||||||||||
301 | // Returns -1 if an error occurred. | ||||||||||
302 | int IsTensorHelper(PyObject* o) { | ||||||||||
303 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
304 | return IsInstanceOfRegisteredType(to_check, "Tensor"); | ||||||||||
305 | }); | ||||||||||
306 | return check_cache->CachedLookup(o); | ||||||||||
307 | } | ||||||||||
308 | |||||||||||
309 | // Returns 1 if `o` is a TensorSpec. | ||||||||||
310 | // Returns 0 otherwise. | ||||||||||
311 | // Returns -1 if an error occurred. | ||||||||||
312 | int IsTensorSpecHelper(PyObject* o) { | ||||||||||
313 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
314 | return IsInstanceOfRegisteredType(to_check, "TensorSpec"); | ||||||||||
315 | }); | ||||||||||
316 | return check_cache->CachedLookup(o); | ||||||||||
317 | } | ||||||||||
318 | |||||||||||
319 | // Returns 1 if `o` is an EagerTensor. | ||||||||||
320 | // Returns 0 otherwise. | ||||||||||
321 | // Returns -1 if an error occurred. | ||||||||||
322 | int IsEagerTensorHelper(PyObject* o) { | ||||||||||
323 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
324 | return IsInstanceOfRegisteredType(to_check, "EagerTensor"); | ||||||||||
325 | }); | ||||||||||
326 | return check_cache->CachedLookup(o); | ||||||||||
327 | } | ||||||||||
328 | |||||||||||
329 | // Returns 1 if `o` is a ResourceVariable. | ||||||||||
330 | // Returns 0 otherwise. | ||||||||||
331 | // Returns -1 if an error occurred. | ||||||||||
332 | int IsResourceVariableHelper(PyObject* o) { | ||||||||||
333 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
334 | return IsInstanceOfRegisteredType(to_check, "ResourceVariable"); | ||||||||||
335 | }); | ||||||||||
336 | return check_cache->CachedLookup(o); | ||||||||||
337 | } | ||||||||||
338 | |||||||||||
339 | // Returns 1 if `o` is a OwnedIterator. | ||||||||||
340 | // Returns 0 otherwise. | ||||||||||
341 | // Returns -1 if an error occurred. | ||||||||||
342 | int IsOwnedIteratorHelper(PyObject* o) { | ||||||||||
343 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
344 | return IsInstanceOfRegisteredType(to_check, "OwnedIterator"); | ||||||||||
345 | }); | ||||||||||
346 | return check_cache->CachedLookup(o); | ||||||||||
347 | } | ||||||||||
348 | |||||||||||
349 | // Returns 1 if `o` is a ResourceVariable. | ||||||||||
350 | // Returns 0 otherwise. | ||||||||||
351 | // Returns -1 if an error occurred. | ||||||||||
352 | int IsVariableHelper(PyObject* o) { | ||||||||||
353 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
354 | return IsInstanceOfRegisteredType(to_check, "Variable"); | ||||||||||
355 | }); | ||||||||||
356 | return check_cache->CachedLookup(o); | ||||||||||
357 | } | ||||||||||
358 | |||||||||||
359 | // Returns 1 if `o` is considered a sequence for the purposes of Flatten(). | ||||||||||
360 | // Returns 0 otherwise. | ||||||||||
361 | // Returns -1 if an error occurred. | ||||||||||
362 | int IsSequenceHelper(PyObject* o) { | ||||||||||
363 | // We treat dicts and other mappings as special cases of sequences. | ||||||||||
364 | if (IsMappingHelper(o)) return true; | ||||||||||
365 | if (IsMappingViewHelper(o)) return true; | ||||||||||
366 | if (IsAttrsHelper(o)) return true; | ||||||||||
367 | if (PySet_Check(o)((((PyObject*)(o))->ob_type) == &PySet_Type || PyType_IsSubtype ((((PyObject*)(o))->ob_type), &PySet_Type)) && !WarnedThatSetIsNotSequence) { | ||||||||||
368 | LOG(WARNING)::tensorflow::internal::LogMessage("tensorflow/python/util/util.cc" , 368, ::tensorflow::WARNING) << "Sets are not currently considered sequences, " | ||||||||||
369 | "but this may change in the future, " | ||||||||||
370 | "so consider avoiding using them."; | ||||||||||
371 | WarnedThatSetIsNotSequence = true; | ||||||||||
372 | } | ||||||||||
373 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
374 | int is_instance = IsInstanceOfRegisteredType(to_check, "Sequence"); | ||||||||||
375 | |||||||||||
376 | // Don't cache a failed is_instance check. | ||||||||||
377 | if (is_instance == -1) return -1; | ||||||||||
378 | |||||||||||
379 | return static_cast<int>(is_instance != 0 && !IsString(to_check)); | ||||||||||
380 | }); | ||||||||||
381 | return check_cache->CachedLookup(o); | ||||||||||
382 | } | ||||||||||
383 | |||||||||||
384 | // Returns 1 if `o`'s class has a `__tf_dispatch__` attribute. | ||||||||||
385 | // Returns 0 otherwise. | ||||||||||
386 | int IsDispatchableHelper(PyObject* o) { | ||||||||||
387 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
388 | return PyObject_HasAttrString( | ||||||||||
389 | reinterpret_cast<PyObject*>(to_check->ob_type), "__tf_dispatch__"); | ||||||||||
390 | }); | ||||||||||
391 | return check_cache->CachedLookup(o); | ||||||||||
392 | } | ||||||||||
393 | |||||||||||
394 | // ValueIterator interface | ||||||||||
395 | class ValueIterator { | ||||||||||
396 | public: | ||||||||||
397 | virtual ~ValueIterator() {} | ||||||||||
398 | virtual Safe_PyObjectPtr next() = 0; | ||||||||||
399 | |||||||||||
400 | bool valid() const { return is_valid_; } | ||||||||||
401 | |||||||||||
402 | protected: | ||||||||||
403 | void invalidate() { is_valid_ = false; } | ||||||||||
404 | |||||||||||
405 | private: | ||||||||||
406 | bool is_valid_ = true; | ||||||||||
407 | }; | ||||||||||
408 | |||||||||||
409 | using ValueIteratorPtr = std::unique_ptr<ValueIterator>; | ||||||||||
410 | |||||||||||
411 | // Iterate through dictionaries in a deterministic order by sorting the | ||||||||||
412 | // keys. Notice this means that we ignore the original order of | ||||||||||
413 | // `OrderedDict` instances. This is intentional, to avoid potential | ||||||||||
414 | // bugs caused by mixing ordered and plain dicts (e.g., flattening | ||||||||||
415 | // a dict but using a corresponding `OrderedDict` to pack it back). | ||||||||||
416 | class DictValueIterator : public ValueIterator { | ||||||||||
417 | public: | ||||||||||
418 | explicit DictValueIterator(PyObject* dict) | ||||||||||
419 | : dict_(dict), keys_(PyDict_Keys(dict)) { | ||||||||||
420 | if (PyList_Sort(keys_.get()) == -1) { | ||||||||||
421 | invalidate(); | ||||||||||
422 | } else { | ||||||||||
423 | iter_.reset(PyObject_GetIter(keys_.get())); | ||||||||||
424 | } | ||||||||||
425 | } | ||||||||||
426 | |||||||||||
427 | Safe_PyObjectPtr next() override { | ||||||||||
428 | Safe_PyObjectPtr result; | ||||||||||
429 | Safe_PyObjectPtr key(PyIter_Next(iter_.get())); | ||||||||||
430 | if (key) { | ||||||||||
431 | // PyDict_GetItem returns a borrowed reference. | ||||||||||
432 | PyObject* elem = PyDict_GetItem(dict_, key.get()); | ||||||||||
433 | if (elem) { | ||||||||||
434 | Py_INCREF(elem)_Py_INCREF(((PyObject*)(elem))); | ||||||||||
435 | result.reset(elem); | ||||||||||
436 | } else { | ||||||||||
437 | PyErr_SetString(PyExc_RuntimeError, | ||||||||||
438 | "Dictionary was modified during iteration over it"); | ||||||||||
439 | } | ||||||||||
440 | } | ||||||||||
441 | return result; | ||||||||||
442 | } | ||||||||||
443 | |||||||||||
444 | private: | ||||||||||
445 | PyObject* dict_; | ||||||||||
446 | Safe_PyObjectPtr keys_; | ||||||||||
447 | Safe_PyObjectPtr iter_; | ||||||||||
448 | }; | ||||||||||
449 | |||||||||||
450 | // Iterate over mapping objects by sorting the keys first | ||||||||||
451 | class MappingValueIterator : public ValueIterator { | ||||||||||
452 | public: | ||||||||||
453 | explicit MappingValueIterator(PyObject* mapping) | ||||||||||
454 | : mapping_(mapping), keys_(MappingKeys(mapping)) { | ||||||||||
455 | if (!keys_ || PyList_Sort(keys_.get()) == -1) { | ||||||||||
456 | invalidate(); | ||||||||||
457 | } else { | ||||||||||
458 | iter_.reset(PyObject_GetIter(keys_.get())); | ||||||||||
459 | } | ||||||||||
460 | } | ||||||||||
461 | |||||||||||
462 | Safe_PyObjectPtr next() override { | ||||||||||
463 | Safe_PyObjectPtr result; | ||||||||||
464 | Safe_PyObjectPtr key(PyIter_Next(iter_.get())); | ||||||||||
465 | if (key) { | ||||||||||
466 | // Unlike PyDict_GetItem, PyObject_GetItem returns a new reference. | ||||||||||
467 | PyObject* elem = PyObject_GetItem(mapping_, key.get()); | ||||||||||
468 | if (elem) { | ||||||||||
469 | result.reset(elem); | ||||||||||
470 | } else { | ||||||||||
471 | PyErr_SetString(PyExc_RuntimeError, | ||||||||||
472 | "Mapping was modified during iteration over it"); | ||||||||||
473 | } | ||||||||||
474 | } | ||||||||||
475 | return result; | ||||||||||
476 | } | ||||||||||
477 | |||||||||||
478 | private: | ||||||||||
479 | PyObject* mapping_; | ||||||||||
480 | Safe_PyObjectPtr keys_; | ||||||||||
481 | Safe_PyObjectPtr iter_; | ||||||||||
482 | }; | ||||||||||
483 | |||||||||||
484 | // Iterate over a sequence, by index. | ||||||||||
485 | class SequenceValueIterator : public ValueIterator { | ||||||||||
486 | public: | ||||||||||
487 | explicit SequenceValueIterator(PyObject* iterable) | ||||||||||
488 | : seq_(PySequence_Fast(iterable, "")), | ||||||||||
489 | size_(seq_.get() ? PySequence_Fast_GET_SIZE(seq_.get())(((((((PyObject*)(seq_.get()))->ob_type))->tp_flags & ((1UL << 25))) != 0) ? ((static_cast<void> (0)), (((PyVarObject*)(seq_.get()))->ob_size)) : (((PyVarObject *)(((static_cast<void> (0)), (PyTupleObject *)(seq_.get ()))))->ob_size)) : 0), | ||||||||||
490 | index_(0) {} | ||||||||||
491 | |||||||||||
492 | Safe_PyObjectPtr next() override { | ||||||||||
493 | Safe_PyObjectPtr result; | ||||||||||
494 | if (index_ < size_) { | ||||||||||
495 | // PySequence_Fast_GET_ITEM returns a borrowed reference. | ||||||||||
496 | PyObject* elem = PySequence_Fast_GET_ITEM(seq_.get(), index_)(((((((PyObject*)(seq_.get()))->ob_type))->tp_flags & ((1UL << 25))) != 0) ? (((PyListObject *)(seq_.get())) ->ob_item[index_]) : (((static_cast<void> (0)), (PyTupleObject *)(seq_.get()))->ob_item[index_])); | ||||||||||
497 | ++index_; | ||||||||||
498 | if (elem) { | ||||||||||
499 | Py_INCREF(elem)_Py_INCREF(((PyObject*)(elem))); | ||||||||||
500 | result.reset(elem); | ||||||||||
501 | } | ||||||||||
502 | } | ||||||||||
503 | |||||||||||
504 | return result; | ||||||||||
505 | } | ||||||||||
506 | |||||||||||
507 | private: | ||||||||||
508 | Safe_PyObjectPtr seq_; | ||||||||||
509 | const Py_ssize_t size_; | ||||||||||
510 | Py_ssize_t index_; | ||||||||||
511 | }; | ||||||||||
512 | |||||||||||
513 | // Iterator that just returns a single python object. | ||||||||||
514 | class SingleValueIterator : public ValueIterator { | ||||||||||
515 | public: | ||||||||||
516 | explicit SingleValueIterator(PyObject* x) : x_(x) { Py_INCREF(x)_Py_INCREF(((PyObject*)(x))); } | ||||||||||
517 | |||||||||||
518 | Safe_PyObjectPtr next() override { return std::move(x_); } | ||||||||||
519 | |||||||||||
520 | private: | ||||||||||
521 | Safe_PyObjectPtr x_; | ||||||||||
522 | }; | ||||||||||
523 | |||||||||||
524 | // Returns nullptr (to raise an exception) when next() is called. Caller | ||||||||||
525 | // should have already called PyErr_SetString. | ||||||||||
526 | class ErrorValueIterator : public ValueIterator { | ||||||||||
527 | public: | ||||||||||
528 | ErrorValueIterator() {} | ||||||||||
529 | Safe_PyObjectPtr next() override { return nullptr; } | ||||||||||
530 | }; | ||||||||||
531 | |||||||||||
532 | class AttrsValueIterator : public ValueIterator { | ||||||||||
533 | public: | ||||||||||
534 | explicit AttrsValueIterator(PyObject* nested) : nested_(nested) { | ||||||||||
535 | Py_INCREF(nested)_Py_INCREF(((PyObject*)(nested))); | ||||||||||
536 | cls_.reset(PyObject_GetAttrString(nested_.get(), "__class__")); | ||||||||||
537 | if (cls_) { | ||||||||||
538 | attrs_.reset(PyObject_GetAttrString(cls_.get(), "__attrs_attrs__")); | ||||||||||
539 | if (attrs_) { | ||||||||||
540 | iter_.reset(PyObject_GetIter(attrs_.get())); | ||||||||||
| |||||||||||
541 | } | ||||||||||
542 | } | ||||||||||
543 | if (!iter_ || PyErr_Occurred()) invalidate(); | ||||||||||
544 | } | ||||||||||
545 | |||||||||||
546 | Safe_PyObjectPtr next() override { | ||||||||||
547 | Safe_PyObjectPtr result; | ||||||||||
548 | Safe_PyObjectPtr item(PyIter_Next(iter_.get())); | ||||||||||
549 | if (item) { | ||||||||||
550 | Safe_PyObjectPtr name(PyObject_GetAttrString(item.get(), "name")); | ||||||||||
551 | result.reset(PyObject_GetAttr(nested_.get(), name.get())); | ||||||||||
552 | } | ||||||||||
553 | |||||||||||
554 | return result; | ||||||||||
555 | } | ||||||||||
556 | |||||||||||
557 | private: | ||||||||||
558 | Safe_PyObjectPtr nested_; | ||||||||||
559 | Safe_PyObjectPtr cls_; | ||||||||||
560 | Safe_PyObjectPtr attrs_; | ||||||||||
561 | Safe_PyObjectPtr iter_; | ||||||||||
562 | }; | ||||||||||
563 | |||||||||||
564 | bool IsSparseTensorValueType(PyObject* o) { | ||||||||||
565 | PyObject* sparse_tensor_value_type = | ||||||||||
566 | GetRegisteredPyObject("SparseTensorValue"); | ||||||||||
567 | if (TF_PREDICT_FALSE(sparse_tensor_value_type == nullptr)(__builtin_expect(sparse_tensor_value_type == nullptr, 0))) { | ||||||||||
568 | return false; | ||||||||||
569 | } | ||||||||||
570 | |||||||||||
571 | return PyObject_TypeCheck(((((PyObject*)(o))->ob_type) == (reinterpret_cast<PyTypeObject *>(sparse_tensor_value_type)) || PyType_IsSubtype((((PyObject *)(o))->ob_type), (reinterpret_cast<PyTypeObject*>(sparse_tensor_value_type )))) | ||||||||||
572 | o, reinterpret_cast<PyTypeObject*>(sparse_tensor_value_type))((((PyObject*)(o))->ob_type) == (reinterpret_cast<PyTypeObject *>(sparse_tensor_value_type)) || PyType_IsSubtype((((PyObject *)(o))->ob_type), (reinterpret_cast<PyTypeObject*>(sparse_tensor_value_type )))) == 1; | ||||||||||
573 | } | ||||||||||
574 | |||||||||||
575 | // Returns 1 if `o` is an instance of CompositeTensor. | ||||||||||
576 | // Returns 0 otherwise. | ||||||||||
577 | // Returns -1 if an error occurred. | ||||||||||
578 | bool IsCompositeTensorHelper(PyObject* o) { | ||||||||||
579 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
580 | return IsInstanceOfRegisteredType(to_check, "CompositeTensor"); | ||||||||||
581 | }); | ||||||||||
582 | return check_cache->CachedLookup(o); | ||||||||||
583 | } | ||||||||||
584 | |||||||||||
585 | // Returns 1 if `o` is an instance of TypeSpec, but is not TensorSpec or | ||||||||||
586 | // VariableSpec. | ||||||||||
587 | // Returns 0 otherwise. | ||||||||||
588 | // Returns -1 if an error occurred. | ||||||||||
589 | bool IsTypeSpecHelper(PyObject* o) { | ||||||||||
590 | static auto* const check_cache = new CachedTypeCheck([](PyObject* to_check) { | ||||||||||
591 | int is_type_spec = IsInstanceOfRegisteredType(to_check, "TypeSpec"); | ||||||||||
592 | int is_dense_spec = (IsInstanceOfRegisteredType(to_check, "TensorSpec") || | ||||||||||
593 | IsInstanceOfRegisteredType(to_check, "VariableSpec")); | ||||||||||
594 | if ((is_type_spec == -1) || (is_dense_spec == -1)) return -1; | ||||||||||
595 | return static_cast<int>(is_type_spec && !is_dense_spec); | ||||||||||
596 | }); | ||||||||||
597 | return check_cache->CachedLookup(o); | ||||||||||
598 | } | ||||||||||
599 | |||||||||||
600 | // Returns 1 if `o` is a (non-string) sequence or CompositeTensor or | ||||||||||
601 | // (non-TensorSpec and non-VariableSpec) TypeSpec. | ||||||||||
602 | // Returns 0 otherwise. | ||||||||||
603 | // Returns -1 if an error occurred. | ||||||||||
604 | int IsSequenceOrCompositeHelper(PyObject* o) { | ||||||||||
605 | int is_sequence = IsSequenceHelper(o); | ||||||||||
606 | int is_composite = IsCompositeTensorHelper(o); | ||||||||||
607 | int is_type_spec = IsTypeSpecHelper(o); | ||||||||||
608 | if ((is_sequence == -1) || (is_composite == -1) || (is_type_spec == -1)) { | ||||||||||
609 | return -1; | ||||||||||
610 | } | ||||||||||
611 | return is_sequence || is_composite || is_type_spec; | ||||||||||
612 | } | ||||||||||
613 | |||||||||||
614 | int IsSequenceForDataHelper(PyObject* o) { | ||||||||||
615 | return IsSequenceHelper(o) == 1 && !PyList_Check(o)((((((PyObject*)(o))->ob_type))->tp_flags & ((1UL << 25))) != 0) && | ||||||||||
616 | !IsSparseTensorValueType(o); | ||||||||||
617 | } | ||||||||||
618 | |||||||||||
619 | ValueIteratorPtr GetValueIterator(PyObject* nested) { | ||||||||||
620 | if (PyDict_Check(nested)((((((PyObject*)(nested))->ob_type))->tp_flags & (( 1UL << 29))) != 0)) { | ||||||||||
621 | return absl::make_unique<DictValueIterator>(nested); | ||||||||||
622 | } else if (IsMappingHelper(nested)) { | ||||||||||
623 | return absl::make_unique<MappingValueIterator>(nested); | ||||||||||
624 | } else if (IsAttrsHelper(nested)) { | ||||||||||
625 | return absl::make_unique<AttrsValueIterator>(nested); | ||||||||||
626 | } else { | ||||||||||
627 | return absl::make_unique<SequenceValueIterator>(nested); | ||||||||||
628 | } | ||||||||||
629 | } | ||||||||||
630 | |||||||||||
631 | // Similar to above, just specialized for the functions in the data package. | ||||||||||
632 | ValueIteratorPtr GetValueIteratorForData(PyObject* nested) { | ||||||||||
633 | if (PyDict_Check(nested)((((((PyObject*)(nested))->ob_type))->tp_flags & (( 1UL << 29))) != 0)) { | ||||||||||
634 | return absl::make_unique<DictValueIterator>(nested); | ||||||||||
635 | } else if (IsMappingHelper(nested)) { | ||||||||||
636 | return absl::make_unique<MappingValueIterator>(nested); | ||||||||||
637 | } else if (IsAttrsHelper(nested)) { | ||||||||||
638 | return absl::make_unique<AttrsValueIterator>(nested); | ||||||||||
639 | } else if (IsSparseTensorValueType(nested)) { | ||||||||||
640 | return absl::make_unique<SingleValueIterator>(nested); | ||||||||||
641 | } else { | ||||||||||
642 | return absl::make_unique<SequenceValueIterator>(nested); | ||||||||||
643 | } | ||||||||||
644 | } | ||||||||||
645 | |||||||||||
646 | // Similar to GetValueIterator above, but expands CompositeTensor and TypeSpec. | ||||||||||
647 | ValueIteratorPtr GetValueIteratorForComposite(PyObject* nested) { | ||||||||||
648 | if (IsCompositeTensor(nested)) { | ||||||||||
649 | Safe_PyObjectPtr spec(PyObject_GetAttrString(nested, "_type_spec")); | ||||||||||
650 | if (PyErr_Occurred() || !spec) { | ||||||||||
651 | return absl::make_unique<ErrorValueIterator>(); | ||||||||||
652 | } | ||||||||||
653 | |||||||||||
654 | static char to_components[] = "_to_components"; | ||||||||||
655 | static char argspec[] = "(O)"; | ||||||||||
656 | Safe_PyObjectPtr components( | ||||||||||
657 | PyObject_CallMethod(spec.get(), to_components, argspec, nested)); | ||||||||||
658 | if (PyErr_Occurred() || components == nullptr) { | ||||||||||
659 | return absl::make_unique<ErrorValueIterator>(); | ||||||||||
660 | } | ||||||||||
661 | return absl::make_unique<SingleValueIterator>(components.get()); | ||||||||||
662 | } | ||||||||||
663 | |||||||||||
664 | if (IsTypeSpec(nested)) { | ||||||||||
665 | Safe_PyObjectPtr specs(PyObject_GetAttrString(nested, "_component_specs")); | ||||||||||
666 | if (PyErr_Occurred() || specs == nullptr) { | ||||||||||
667 | return absl::make_unique<ErrorValueIterator>(); | ||||||||||
668 | } | ||||||||||
669 | return absl::make_unique<SingleValueIterator>(specs.get()); | ||||||||||
670 | } | ||||||||||
671 | |||||||||||
672 | return GetValueIterator(nested); | ||||||||||
673 | } | ||||||||||
674 | |||||||||||
675 | bool FlattenHelper( | ||||||||||
676 | PyObject* nested, PyObject* list, | ||||||||||
677 | const std::function<int(PyObject*)>& is_sequence_helper, | ||||||||||
678 | const std::function<ValueIteratorPtr(PyObject*)>& value_iterator_getter) { | ||||||||||
679 | // if nested is not a sequence, append itself and exit | ||||||||||
680 | int is_seq = is_sequence_helper(nested); | ||||||||||
681 | if (is_seq == -1) return false; | ||||||||||
682 | if (!is_seq
| ||||||||||
683 | return PyList_Append(list, nested) != -1; | ||||||||||
684 | } | ||||||||||
685 | |||||||||||
686 | ValueIteratorPtr iter = value_iterator_getter(nested); | ||||||||||
687 | if (!iter->valid()) return false; | ||||||||||
688 | |||||||||||
689 | for (Safe_PyObjectPtr item = iter->next(); item; item = iter->next()) { | ||||||||||
690 | if (Py_EnterRecursiveCall(" in flatten")((++(PyThreadState_Get()->recursion_depth) > _Py_CheckRecursionLimit ) && _Py_CheckRecursiveCall(" in flatten"))) { | ||||||||||
691 | return false; | ||||||||||
692 | } | ||||||||||
693 | const bool success = FlattenHelper(item.get(), list, is_sequence_helper, | ||||||||||
694 | value_iterator_getter); | ||||||||||
695 | Py_LeaveRecursiveCall()do{ if((--(PyThreadState_Get()->recursion_depth) < (((_Py_CheckRecursionLimit ) > 200) ? ((_Py_CheckRecursionLimit) - 50) : (3 * ((_Py_CheckRecursionLimit ) >> 2))))) PyThreadState_Get()->overflowed = 0; } while (0); | ||||||||||
696 | if (!success) { | ||||||||||
697 | return false; | ||||||||||
698 | } | ||||||||||
699 | } | ||||||||||
700 | return true; | ||||||||||
701 | } | ||||||||||
702 | |||||||||||
703 | // Sets error using keys of 'dict1' and 'dict2'. | ||||||||||
704 | // 'dict1' and 'dict2' are assumed to be Python dictionaries. | ||||||||||
705 | void SetDifferentKeysError(PyObject* dict1, PyObject* dict2, string* error_msg, | ||||||||||
706 | bool* is_type_error) { | ||||||||||
707 | Safe_PyObjectPtr k1(MappingKeys(dict1)); | ||||||||||
708 | if (PyErr_Occurred() || k1.get() == nullptr) { | ||||||||||
709 | *error_msg = | ||||||||||
710 | ("The two dictionaries don't have the same set of keys. Failed to " | ||||||||||
711 | "fetch keys."); | ||||||||||
712 | return; | ||||||||||
713 | } | ||||||||||
714 | Safe_PyObjectPtr k2(MappingKeys(dict2)); | ||||||||||
715 | if (PyErr_Occurred() || k2.get() == nullptr) { | ||||||||||
716 | *error_msg = | ||||||||||
717 | ("The two dictionaries don't have the same set of keys. Failed to " | ||||||||||
718 | "fetch keys."); | ||||||||||
719 | return; | ||||||||||
720 | } | ||||||||||
721 | *is_type_error = false; | ||||||||||
722 | *error_msg = tensorflow::strings::StrCat( | ||||||||||
723 | "The two dictionaries don't have the same set of keys. " | ||||||||||
724 | "First structure has keys ", | ||||||||||
725 | PyObjectToString(k1.get()), ", while second structure has keys ", | ||||||||||
726 | PyObjectToString(k2.get())); | ||||||||||
727 | } | ||||||||||
728 | |||||||||||
729 | // Returns true iff there were no "internal" errors. In other words, | ||||||||||
730 | // errors that has nothing to do with structure checking. | ||||||||||
731 | // If an "internal" error occurred, the appropriate Python error will be | ||||||||||
732 | // set and the caller can propage it directly to the user. | ||||||||||
733 | // | ||||||||||
734 | // Both `error_msg` and `is_type_error` must be non-null. `error_msg` must | ||||||||||
735 | // be empty. | ||||||||||
736 | // Leaves `error_msg` empty if structures matched. Else, fills `error_msg` | ||||||||||
737 | // with appropriate error and sets `is_type_error` to true iff | ||||||||||
738 | // the error to be raised should be TypeError. | ||||||||||
739 | bool AssertSameStructureHelper( | ||||||||||
740 | PyObject* o1, PyObject* o2, bool check_types, string* error_msg, | ||||||||||
741 | bool* is_type_error, | ||||||||||
742 | const std::function<int(PyObject*)>& is_sequence_helper, | ||||||||||
743 | const std::function<ValueIteratorPtr(PyObject*)>& value_iterator_getter, | ||||||||||
744 | bool check_composite_tensor_type_spec) { | ||||||||||
745 | DCHECK(error_msg)while (false && (error_msg)) ::tensorflow::internal:: LogMessageFatal("tensorflow/python/util/util.cc", 745); | ||||||||||
746 | DCHECK(is_type_error)while (false && (is_type_error)) ::tensorflow::internal ::LogMessageFatal("tensorflow/python/util/util.cc", 746); | ||||||||||
747 | const bool is_seq1 = is_sequence_helper(o1); | ||||||||||
748 | const bool is_seq2 = is_sequence_helper(o2); | ||||||||||
749 | if (PyErr_Occurred()) return false; | ||||||||||
750 | if (is_seq1 != is_seq2) { | ||||||||||
751 | string seq_str = is_seq1 ? PyObjectToString(o1) : PyObjectToString(o2); | ||||||||||
752 | string non_seq_str = is_seq1 ? PyObjectToString(o2) : PyObjectToString(o1); | ||||||||||
753 | *is_type_error = false; | ||||||||||
754 | *error_msg = tensorflow::strings::StrCat( | ||||||||||
755 | "Substructure \"", seq_str, "\" is a sequence, while substructure \"", | ||||||||||
756 | non_seq_str, "\" is not"); | ||||||||||
757 | return true; | ||||||||||
758 | } | ||||||||||
759 | |||||||||||
760 | // Got to objects that are considered non-sequences. Note that in tf.data | ||||||||||
761 | // use case lists and sparse_tensors are not considered sequences. So finished | ||||||||||
762 | // checking, structures are the same. | ||||||||||
763 | if (!is_seq1) return true; | ||||||||||
764 | |||||||||||
765 | if (check_types) { | ||||||||||
766 | // Treat wrapped tuples as tuples. | ||||||||||
767 | tensorflow::Safe_PyObjectPtr o1_wrapped; | ||||||||||
768 | if (IsObjectProxy(o1)) { | ||||||||||
769 | o1_wrapped.reset(PyObject_GetAttrString(o1, "__wrapped__")); | ||||||||||
770 | o1 = o1_wrapped.get(); | ||||||||||
771 | } | ||||||||||
772 | tensorflow::Safe_PyObjectPtr o2_wrapped; | ||||||||||
773 | if (IsObjectProxy(o2)) { | ||||||||||
774 | o2_wrapped.reset(PyObject_GetAttrString(o2, "__wrapped__")); | ||||||||||
775 | o2 = o2_wrapped.get(); | ||||||||||
776 | } | ||||||||||
777 | |||||||||||
778 | const PyTypeObject* type1 = o1->ob_type; | ||||||||||
779 | const PyTypeObject* type2 = o2->ob_type; | ||||||||||
780 | |||||||||||
781 | // We treat two different namedtuples with identical name and fields | ||||||||||
782 | // as having the same type. | ||||||||||
783 | const PyObject* o1_tuple = IsNamedtuple(o1, false); | ||||||||||
784 | if (o1_tuple == nullptr) return false; | ||||||||||
785 | const PyObject* o2_tuple = IsNamedtuple(o2, false); | ||||||||||
786 | if (o2_tuple == nullptr) { | ||||||||||
787 | Py_DECREF(o1_tuple)_Py_DECREF(((PyObject*)(o1_tuple))); | ||||||||||
788 | return false; | ||||||||||
789 | } | ||||||||||
790 | bool both_tuples = o1_tuple == Py_True((PyObject *) &_Py_TrueStruct) && o2_tuple == Py_True((PyObject *) &_Py_TrueStruct); | ||||||||||
791 | Py_DECREF(o1_tuple)_Py_DECREF(((PyObject*)(o1_tuple))); | ||||||||||
792 | Py_DECREF(o2_tuple)_Py_DECREF(((PyObject*)(o2_tuple))); | ||||||||||
793 | |||||||||||
794 | if (both_tuples) { | ||||||||||
795 | const PyObject* same_tuples = SameNamedtuples(o1, o2); | ||||||||||
796 | if (same_tuples == nullptr) return false; | ||||||||||
797 | bool not_same_tuples = same_tuples != Py_True((PyObject *) &_Py_TrueStruct); | ||||||||||
798 | Py_DECREF(same_tuples)_Py_DECREF(((PyObject*)(same_tuples))); | ||||||||||
799 | if (not_same_tuples) { | ||||||||||
800 | *is_type_error = true; | ||||||||||
801 | *error_msg = tensorflow::strings::StrCat( | ||||||||||
802 | "The two namedtuples don't have the same sequence type. " | ||||||||||
803 | "First structure ", | ||||||||||
804 | PyObjectToString(o1), " has type ", type1->tp_name, | ||||||||||
805 | ", while second structure ", PyObjectToString(o2), " has type ", | ||||||||||
806 | type2->tp_name); | ||||||||||
807 | return true; | ||||||||||
808 | } | ||||||||||
809 | } else if (type1 != type2 | ||||||||||
810 | /* If both sequences are list types, don't complain. This allows | ||||||||||
811 | one to be a list subclass (e.g. _ListWrapper used for | ||||||||||
812 | automatic dependency tracking.) */ | ||||||||||
813 | && !(PyList_Check(o1)((((((PyObject*)(o1))->ob_type))->tp_flags & ((1UL << 25))) != 0) && PyList_Check(o2)((((((PyObject*)(o2))->ob_type))->tp_flags & ((1UL << 25))) != 0)) | ||||||||||
814 | /* Two mapping types will also compare equal, making _DictWrapper | ||||||||||
815 | and dict compare equal. */ | ||||||||||
816 | && !(IsMappingHelper(o1) && IsMappingHelper(o2)) | ||||||||||
817 | /* For CompositeTensor & TypeSpec, we check below. */ | ||||||||||
818 | && !(check_composite_tensor_type_spec && | ||||||||||
819 | (IsCompositeTensor(o1) || IsCompositeTensor(o2)) && | ||||||||||
820 | (IsTypeSpec(o1) || IsTypeSpec(o2)))) { | ||||||||||
821 | *is_type_error = true; | ||||||||||
822 | *error_msg = tensorflow::strings::StrCat( | ||||||||||
823 | "The two namedtuples don't have the same sequence type. " | ||||||||||
824 | "First structure ", | ||||||||||
825 | PyObjectToString(o1), " has type ", type1->tp_name, | ||||||||||
826 | ", while second structure ", PyObjectToString(o2), " has type ", | ||||||||||
827 | type2->tp_name); | ||||||||||
828 | return true; | ||||||||||
829 | } | ||||||||||
830 | |||||||||||
831 | if (PyDict_Check(o1)((((((PyObject*)(o1))->ob_type))->tp_flags & ((1UL << 29))) != 0) && PyDict_Check(o2)((((((PyObject*)(o2))->ob_type))->tp_flags & ((1UL << 29))) != 0)) { | ||||||||||
832 | if (PyDict_Size(o1) != PyDict_Size(o2)) { | ||||||||||
833 | SetDifferentKeysError(o1, o2, error_msg, is_type_error); | ||||||||||
834 | return true; | ||||||||||
835 | } | ||||||||||
836 | |||||||||||
837 | PyObject* key; | ||||||||||
838 | Py_ssize_t pos = 0; | ||||||||||
839 | while (PyDict_Next(o1, &pos, &key, nullptr)) { | ||||||||||
840 | if (PyDict_GetItem(o2, key) == nullptr) { | ||||||||||
841 | SetDifferentKeysError(o1, o2, error_msg, is_type_error); | ||||||||||
842 | return true; | ||||||||||
843 | } | ||||||||||
844 | } | ||||||||||
845 | } else if (IsMappingHelper(o1)) { | ||||||||||
846 | // Fallback for custom mapping types. Instead of using PyDict methods | ||||||||||
847 | // which stay in C, we call iter(o1). | ||||||||||
848 | if (PyMapping_Size(o1) != PyMapping_Size(o2)) { | ||||||||||
849 | SetDifferentKeysError(o1, o2, error_msg, is_type_error); | ||||||||||
850 | return true; | ||||||||||
851 | } | ||||||||||
852 | |||||||||||
853 | Safe_PyObjectPtr iter(PyObject_GetIter(o1)); | ||||||||||
854 | PyObject* key; | ||||||||||
855 | while ((key = PyIter_Next(iter.get())) != nullptr) { | ||||||||||
856 | if (!PyMapping_HasKey(o2, key)) { | ||||||||||
857 | SetDifferentKeysError(o1, o2, error_msg, is_type_error); | ||||||||||
858 | Py_DECREF(key)_Py_DECREF(((PyObject*)(key))); | ||||||||||
859 | return true; | ||||||||||
860 | } | ||||||||||
861 | Py_DECREF(key)_Py_DECREF(((PyObject*)(key))); | ||||||||||
862 | } | ||||||||||
863 | } | ||||||||||
864 | } | ||||||||||
865 | |||||||||||
866 | if (check_composite_tensor_type_spec && | ||||||||||
867 | (IsCompositeTensor(o1) || IsCompositeTensor(o2))) { | ||||||||||
868 | Safe_PyObjectPtr owned_type_spec_1; | ||||||||||
869 | PyObject* type_spec_1 = o1; | ||||||||||
870 | if (IsCompositeTensor(o1)) { | ||||||||||
871 | owned_type_spec_1.reset(PyObject_GetAttrString(o1, "_type_spec")); | ||||||||||
872 | type_spec_1 = owned_type_spec_1.get(); | ||||||||||
873 | } | ||||||||||
874 | |||||||||||
875 | Safe_PyObjectPtr owned_type_spec_2; | ||||||||||
876 | PyObject* type_spec_2 = o2; | ||||||||||
877 | if (IsCompositeTensor(o2)) { | ||||||||||
878 | owned_type_spec_2.reset(PyObject_GetAttrString(o2, "_type_spec")); | ||||||||||
879 | type_spec_2 = owned_type_spec_2.get(); | ||||||||||
880 | } | ||||||||||
881 | |||||||||||
882 | // Two composite tensors are considered to have the same structure if | ||||||||||
883 | // there is some type spec that is compatible with both of them. Thus, | ||||||||||
884 | // we use most_specific_compatible_type(), and check if it raises an | ||||||||||
885 | // exception. We do *not* use is_compatible_with, since that would | ||||||||||
886 | // prevent us from e.g. using a cond statement where the two sides have | ||||||||||
887 | // different shapes. | ||||||||||
888 | static char compatible_type[] = "most_specific_compatible_type"; | ||||||||||
889 | static char argspec[] = "(O)"; | ||||||||||
890 | Safe_PyObjectPtr struct_compatible(PyObject_CallMethod( | ||||||||||
891 | type_spec_1, compatible_type, argspec, type_spec_2)); | ||||||||||
892 | if (PyErr_Occurred() || struct_compatible == nullptr) { | ||||||||||
893 | PyErr_Clear(); | ||||||||||
894 | *is_type_error = false; | ||||||||||
895 | *error_msg = tensorflow::strings::StrCat( | ||||||||||
896 | "Incompatible CompositeTensor TypeSpecs: ", | ||||||||||
897 | PyObjectToString(type_spec_1), " vs. ", | ||||||||||
898 | PyObjectToString(type_spec_2)); | ||||||||||
899 | return true; | ||||||||||
900 | } | ||||||||||
901 | } | ||||||||||
902 | |||||||||||
903 | ValueIteratorPtr iter1 = value_iterator_getter(o1); | ||||||||||
904 | ValueIteratorPtr iter2 = value_iterator_getter(o2); | ||||||||||
905 | |||||||||||
906 | if (!iter1->valid() || !iter2->valid()) return false; | ||||||||||
907 | |||||||||||
908 | while (true) { | ||||||||||
909 | Safe_PyObjectPtr v1 = iter1->next(); | ||||||||||
910 | Safe_PyObjectPtr v2 = iter2->next(); | ||||||||||
911 | if (v1 && v2) { | ||||||||||
912 | if (Py_EnterRecursiveCall(" in assert_same_structure")((++(PyThreadState_Get()->recursion_depth) > _Py_CheckRecursionLimit ) && _Py_CheckRecursiveCall(" in assert_same_structure" ))) { | ||||||||||
913 | return false; | ||||||||||
914 | } | ||||||||||
915 | bool no_internal_errors = AssertSameStructureHelper( | ||||||||||
916 | v1.get(), v2.get(), check_types, error_msg, is_type_error, | ||||||||||
917 | is_sequence_helper, value_iterator_getter, | ||||||||||
918 | check_composite_tensor_type_spec); | ||||||||||
919 | Py_LeaveRecursiveCall()do{ if((--(PyThreadState_Get()->recursion_depth) < (((_Py_CheckRecursionLimit ) > 200) ? ((_Py_CheckRecursionLimit) - 50) : (3 * ((_Py_CheckRecursionLimit ) >> 2))))) PyThreadState_Get()->overflowed = 0; } while (0); | ||||||||||
920 | if (!no_internal_errors) return false; | ||||||||||
921 | if (!error_msg->empty()) return true; | ||||||||||
922 | } else if (!v1 && !v2) { | ||||||||||
923 | // Done with all recursive calls. Structure matched. | ||||||||||
924 | return true; | ||||||||||
925 | } else { | ||||||||||
926 | *is_type_error = false; | ||||||||||
927 | *error_msg = tensorflow::strings::StrCat( | ||||||||||
928 | "The two structures don't have the same number of elements. ", | ||||||||||
929 | "First structure: ", PyObjectToString(o1), | ||||||||||
930 | ". Second structure: ", PyObjectToString(o2)); | ||||||||||
931 | return true; | ||||||||||
932 | } | ||||||||||
933 | } | ||||||||||
934 | } | ||||||||||
935 | |||||||||||
936 | } // namespace | ||||||||||
937 | |||||||||||
938 | bool IsSequence(PyObject* o) { return IsSequenceHelper(o) == 1; } | ||||||||||
939 | bool IsMapping(PyObject* o) { return IsMappingHelper(o) == 1; } | ||||||||||
940 | bool IsMutableMapping(PyObject* o) { return IsMutableMappingHelper(o) == 1; } | ||||||||||
941 | bool IsMappingView(PyObject* o) { return IsMappingViewHelper(o) == 1; } | ||||||||||
942 | bool IsAttrs(PyObject* o) { return IsAttrsHelper(o) == 1; } | ||||||||||
943 | bool IsTensor(PyObject* o) { return IsTensorHelper(o) == 1; } | ||||||||||
944 | bool IsTensorSpec(PyObject* o) { return IsTensorSpecHelper(o) == 1; } | ||||||||||
945 | bool IsEagerTensorSlow(PyObject* o) { return IsEagerTensorHelper(o) == 1; } | ||||||||||
946 | bool IsResourceVariable(PyObject* o) { | ||||||||||
947 | return IsResourceVariableHelper(o) == 1; | ||||||||||
948 | } | ||||||||||
949 | bool IsOwnedIterator(PyObject* o) { return IsOwnedIteratorHelper(o) == 1; } | ||||||||||
950 | bool IsVariable(PyObject* o) { return IsVariableHelper(o) == 1; } | ||||||||||
951 | bool IsIndexedSlices(PyObject* o) { return IsIndexedSlicesHelper(o) == 1; } | ||||||||||
952 | bool IsDispatchable(PyObject* o) { return IsDispatchableHelper(o) == 1; } | ||||||||||
953 | |||||||||||
954 | bool IsTuple(PyObject* o) { | ||||||||||
955 | tensorflow::Safe_PyObjectPtr wrapped; | ||||||||||
956 | if (IsObjectProxy(o)) { | ||||||||||
957 | wrapped.reset(PyObject_GetAttrString(o, "__wrapped__")); | ||||||||||
958 | o = wrapped.get(); | ||||||||||
959 | } | ||||||||||
960 | return PyTuple_Check(o)((((((PyObject*)(o))->ob_type))->tp_flags & ((1UL << 26))) != 0); | ||||||||||
961 | } | ||||||||||
962 | |||||||||||
963 | // Work around a writable-strings warning with Python 2's PyMapping_Keys macro, | ||||||||||
964 | // and while we're at it give them consistent behavior by making sure the | ||||||||||
965 | // returned value is a list. | ||||||||||
966 | // | ||||||||||
967 | // As with PyMapping_Keys, returns a new reference. | ||||||||||
968 | // | ||||||||||
969 | // On failure, returns nullptr. | ||||||||||
970 | PyObject* MappingKeys(PyObject* o) { | ||||||||||
971 | #if PY_MAJOR_VERSION3 >= 3 | ||||||||||
972 | return PyMapping_Keys(o); | ||||||||||
973 | #else | ||||||||||
974 | static char key_method_name[] = "keys"; | ||||||||||
975 | Safe_PyObjectPtr raw_result(PyObject_CallMethod(o, key_method_name, nullptr)); | ||||||||||
976 | if (PyErr_Occurred() || raw_result.get() == nullptr) { | ||||||||||
977 | return nullptr; | ||||||||||
978 | } | ||||||||||
979 | return PySequence_Fast( | ||||||||||
980 | raw_result.get(), | ||||||||||
981 | "The '.keys()' method of a custom mapping returned a non-sequence."); | ||||||||||
982 | #endif | ||||||||||
983 | } | ||||||||||
984 | |||||||||||
985 | PyObject* Flatten(PyObject* nested, bool expand_composites) { | ||||||||||
986 | PyObject* list = PyList_New(0); | ||||||||||
987 | const std::function<int(PyObject*)>& is_sequence_helper = | ||||||||||
988 | expand_composites ? IsSequenceOrCompositeHelper : IsSequenceHelper; | ||||||||||
989 | const std::function<ValueIteratorPtr(PyObject*)>& get_value_iterator = | ||||||||||
990 | expand_composites ? GetValueIteratorForComposite : GetValueIterator; | ||||||||||
991 | if (FlattenHelper(nested, list, is_sequence_helper, get_value_iterator)) { | ||||||||||
992 | return list; | ||||||||||
993 | } else { | ||||||||||
994 | Py_DECREF(list)_Py_DECREF(((PyObject*)(list))); | ||||||||||
995 | return nullptr; | ||||||||||
996 | } | ||||||||||
997 | } | ||||||||||
998 | |||||||||||
999 | bool IsSequenceOrComposite(PyObject* o) { | ||||||||||
1000 | return IsSequenceOrCompositeHelper(o) == 1; | ||||||||||
1001 | } | ||||||||||
1002 | |||||||||||
1003 | bool IsCompositeTensor(PyObject* o) { return IsCompositeTensorHelper(o) == 1; } | ||||||||||
1004 | |||||||||||
1005 | bool IsTypeSpec(PyObject* o) { return IsTypeSpecHelper(o) == 1; } | ||||||||||
1006 | |||||||||||
1007 | bool IsSequenceForData(PyObject* o) { return IsSequenceForDataHelper(o) == 1; } | ||||||||||
1008 | |||||||||||
1009 | PyObject* FlattenForData(PyObject* nested) { | ||||||||||
1010 | PyObject* list = PyList_New(0); | ||||||||||
1011 | if (FlattenHelper(nested, list, IsSequenceForDataHelper, | ||||||||||
| |||||||||||
1012 | GetValueIteratorForData)) { | ||||||||||
1013 | return list; | ||||||||||
1014 | } else { | ||||||||||
1015 | Py_DECREF(list)_Py_DECREF(((PyObject*)(list))); | ||||||||||
1016 | return nullptr; | ||||||||||
1017 | } | ||||||||||
1018 | } | ||||||||||
1019 | |||||||||||
1020 | PyObject* IsNamedtuple(PyObject* o, bool strict) { | ||||||||||
1021 | // Some low-level CPython calls do not work with wrapt.ObjectProxy, so they | ||||||||||
1022 | // require some unwrapping if we want to treat them like the objects they're | ||||||||||
1023 | // wrapping. | ||||||||||
1024 | tensorflow::Safe_PyObjectPtr o_wrapped; | ||||||||||
1025 | if (IsObjectProxy(o)) { | ||||||||||
1026 | o_wrapped.reset(PyObject_GetAttrString(o, "__wrapped__")); | ||||||||||
1027 | o = o_wrapped.get(); | ||||||||||
1028 | } | ||||||||||
1029 | |||||||||||
1030 | // Must be subclass of tuple | ||||||||||
1031 | if (!PyTuple_Check(o)((((((PyObject*)(o))->ob_type))->tp_flags & ((1UL << 26))) != 0)) { | ||||||||||
1032 | Py_RETURN_FALSEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_FalseStruct )))), ((PyObject *) &_Py_FalseStruct); | ||||||||||
1033 | } | ||||||||||
1034 | |||||||||||
1035 | // If strict, o.__class__.__base__ must be tuple | ||||||||||
1036 | if (strict) { | ||||||||||
1037 | PyObject* klass = PyObject_GetAttrString(o, "__class__"); | ||||||||||
1038 | if (klass == nullptr) return nullptr; | ||||||||||
1039 | PyObject* base = PyObject_GetAttrString(klass, "__base__"); | ||||||||||
1040 | Py_DECREF(klass)_Py_DECREF(((PyObject*)(klass))); | ||||||||||
1041 | if (base == nullptr) return nullptr; | ||||||||||
1042 | |||||||||||
1043 | const PyTypeObject* base_type = reinterpret_cast<PyTypeObject*>(base); | ||||||||||
1044 | // built-in object types are singletons | ||||||||||
1045 | bool tuple_base = base_type == &PyTuple_Type; | ||||||||||
1046 | Py_DECREF(base)_Py_DECREF(((PyObject*)(base))); | ||||||||||
1047 | if (!tuple_base) { | ||||||||||
1048 | Py_RETURN_FALSEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_FalseStruct )))), ((PyObject *) &_Py_FalseStruct); | ||||||||||
1049 | } | ||||||||||
1050 | } | ||||||||||
1051 | |||||||||||
1052 | // o must have attribute '_fields' and every element in | ||||||||||
1053 | // '_fields' must be a string. | ||||||||||
1054 | int has_fields = PyObject_HasAttrString(o, "_fields"); | ||||||||||
1055 | if (!has_fields) { | ||||||||||
1056 | Py_RETURN_FALSEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_FalseStruct )))), ((PyObject *) &_Py_FalseStruct); | ||||||||||
1057 | } | ||||||||||
1058 | |||||||||||
1059 | Safe_PyObjectPtr fields = make_safe(PyObject_GetAttrString(o, "_fields")); | ||||||||||
1060 | int is_instance = IsInstanceOfRegisteredType(fields.get(), "Sequence"); | ||||||||||
1061 | if (is_instance == 0) { | ||||||||||
1062 | Py_RETURN_FALSEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_FalseStruct )))), ((PyObject *) &_Py_FalseStruct); | ||||||||||
1063 | } else if (is_instance == -1) { | ||||||||||
1064 | return nullptr; | ||||||||||
1065 | } | ||||||||||
1066 | |||||||||||
1067 | Safe_PyObjectPtr seq = make_safe(PySequence_Fast(fields.get(), "")); | ||||||||||
1068 | const Py_ssize_t s = PySequence_Fast_GET_SIZE(seq.get())(((((((PyObject*)(seq.get()))->ob_type))->tp_flags & ((1UL << 25))) != 0) ? ((static_cast<void> (0)), (((PyVarObject*)(seq.get()))->ob_size)) : (((PyVarObject* )(((static_cast<void> (0)), (PyTupleObject *)(seq.get() ))))->ob_size)); | ||||||||||
1069 | for (Py_ssize_t i = 0; i < s; ++i) { | ||||||||||
1070 | // PySequence_Fast_GET_ITEM returns borrowed ref | ||||||||||
1071 | PyObject* elem = PySequence_Fast_GET_ITEM(seq.get(), i)(((((((PyObject*)(seq.get()))->ob_type))->tp_flags & ((1UL << 25))) != 0) ? (((PyListObject *)(seq.get()))-> ob_item[i]) : (((static_cast<void> (0)), (PyTupleObject *)(seq.get()))->ob_item[i])); | ||||||||||
1072 | if (!IsString(elem)) { | ||||||||||
1073 | Py_RETURN_FALSEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_FalseStruct )))), ((PyObject *) &_Py_FalseStruct); | ||||||||||
1074 | } | ||||||||||
1075 | } | ||||||||||
1076 | |||||||||||
1077 | Py_RETURN_TRUEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_TrueStruct )))), ((PyObject *) &_Py_TrueStruct); | ||||||||||
1078 | } | ||||||||||
1079 | |||||||||||
1080 | PyObject* SameNamedtuples(PyObject* o1, PyObject* o2) { | ||||||||||
1081 | Safe_PyObjectPtr f1 = make_safe(PyObject_GetAttrString(o1, "_fields")); | ||||||||||
1082 | Safe_PyObjectPtr f2 = make_safe(PyObject_GetAttrString(o2, "_fields")); | ||||||||||
1083 | if (f1 == nullptr || f2 == nullptr) { | ||||||||||
1084 | PyErr_SetString( | ||||||||||
1085 | PyExc_RuntimeError, | ||||||||||
1086 | "Expected namedtuple-like objects (that have _fields attr)"); | ||||||||||
1087 | return nullptr; | ||||||||||
1088 | } | ||||||||||
1089 | |||||||||||
1090 | if (PyObject_RichCompareBool(f1.get(), f2.get(), Py_NE3)) { | ||||||||||
1091 | Py_RETURN_FALSEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_FalseStruct )))), ((PyObject *) &_Py_FalseStruct); | ||||||||||
1092 | } | ||||||||||
1093 | |||||||||||
1094 | if (GetClassName(o1).compare(GetClassName(o2)) == 0) { | ||||||||||
1095 | Py_RETURN_TRUEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_TrueStruct )))), ((PyObject *) &_Py_TrueStruct); | ||||||||||
1096 | } else { | ||||||||||
1097 | Py_RETURN_FALSEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_FalseStruct )))), ((PyObject *) &_Py_FalseStruct); | ||||||||||
1098 | } | ||||||||||
1099 | } | ||||||||||
1100 | |||||||||||
1101 | PyObject* AssertSameStructure(PyObject* o1, PyObject* o2, bool check_types, | ||||||||||
1102 | bool expand_composites) { | ||||||||||
1103 | const std::function<int(PyObject*)>& is_sequence_helper = | ||||||||||
1104 | expand_composites ? IsSequenceOrCompositeHelper : IsSequenceHelper; | ||||||||||
1105 | const std::function<ValueIteratorPtr(PyObject*)>& get_value_iterator = | ||||||||||
1106 | expand_composites ? GetValueIteratorForComposite : GetValueIterator; | ||||||||||
1107 | const bool check_composite_tensor_type_spec = expand_composites; | ||||||||||
1108 | string error_msg; | ||||||||||
1109 | bool is_type_error = false; | ||||||||||
1110 | AssertSameStructureHelper(o1, o2, check_types, &error_msg, &is_type_error, | ||||||||||
1111 | is_sequence_helper, get_value_iterator, | ||||||||||
1112 | check_composite_tensor_type_spec); | ||||||||||
1113 | if (PyErr_Occurred()) { | ||||||||||
1114 | // Don't hide Python exceptions while checking (e.g. errors fetching keys | ||||||||||
1115 | // from custom mappings). | ||||||||||
1116 | return nullptr; | ||||||||||
1117 | } | ||||||||||
1118 | if (!error_msg.empty()) { | ||||||||||
1119 | PyErr_SetString( | ||||||||||
1120 | is_type_error ? PyExc_TypeError : PyExc_ValueError, | ||||||||||
1121 | tensorflow::strings::StrCat( | ||||||||||
1122 | "The two structures don't have the same nested structure.\n\n", | ||||||||||
1123 | "First structure: ", PyObjectToString(o1), "\n\nSecond structure: ", | ||||||||||
1124 | PyObjectToString(o2), "\n\nMore specifically: ", error_msg) | ||||||||||
1125 | .c_str()); | ||||||||||
1126 | return nullptr; | ||||||||||
1127 | } | ||||||||||
1128 | Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (& _Py_NoneStruct); | ||||||||||
1129 | } | ||||||||||
1130 | |||||||||||
1131 | PyObject* AssertSameStructureForData(PyObject* o1, PyObject* o2, | ||||||||||
1132 | bool check_types) { | ||||||||||
1133 | string error_msg; | ||||||||||
1134 | bool is_type_error = false; | ||||||||||
1135 | AssertSameStructureHelper(o1, o2, check_types, &error_msg, &is_type_error, | ||||||||||
1136 | IsSequenceForDataHelper, GetValueIterator, false); | ||||||||||
1137 | if (PyErr_Occurred()) { | ||||||||||
1138 | // Don't hide Python exceptions while checking (e.g. errors fetching keys | ||||||||||
1139 | // from custom mappings). | ||||||||||
1140 | return nullptr; | ||||||||||
1141 | } | ||||||||||
1142 | if (!error_msg.empty()) { | ||||||||||
1143 | PyErr_SetString( | ||||||||||
1144 | is_type_error ? PyExc_TypeError : PyExc_ValueError, | ||||||||||
1145 | tensorflow::strings::StrCat( | ||||||||||
1146 | "The two structures don't have the same nested structure.\n\n", | ||||||||||
1147 | "First structure: ", PyObjectToString(o1), "\n\nSecond structure: ", | ||||||||||
1148 | PyObjectToString(o2), "\n\nMore specifically: ", error_msg) | ||||||||||
1149 | .c_str()); | ||||||||||
1150 | return nullptr; | ||||||||||
1151 | } | ||||||||||
1152 | Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (& _Py_NoneStruct); | ||||||||||
1153 | } | ||||||||||
1154 | |||||||||||
1155 | } // namespace swig | ||||||||||
1156 | } // namespace tensorflow |
1 | // Implementation of std::function -*- C++ -*- |
2 | |
3 | // Copyright (C) 2004-2020 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file include/bits/std_function.h |
26 | * This is an internal header file, included by other library headers. |
27 | * Do not attempt to use it directly. @headername{functional} |
28 | */ |
29 | |
30 | #ifndef _GLIBCXX_STD_FUNCTION_H1 |
31 | #define _GLIBCXX_STD_FUNCTION_H1 1 |
32 | |
33 | #pragma GCC system_header |
34 | |
35 | #if __cplusplus201402L < 201103L |
36 | # include <bits/c++0x_warning.h> |
37 | #else |
38 | |
39 | #if __cpp_rtti199711L |
40 | # include <typeinfo> |
41 | #endif |
42 | #include <bits/stl_function.h> |
43 | #include <bits/invoke.h> |
44 | #include <bits/refwrap.h> |
45 | #include <bits/functexcept.h> |
46 | |
47 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
48 | { |
49 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
50 | |
51 | /** |
52 | * @brief Exception class thrown when class template function's |
53 | * operator() is called with an empty target. |
54 | * @ingroup exceptions |
55 | */ |
56 | class bad_function_call : public std::exception |
57 | { |
58 | public: |
59 | virtual ~bad_function_call() noexcept; |
60 | |
61 | const char* what() const noexcept; |
62 | }; |
63 | |
64 | /** |
65 | * Trait identifying "location-invariant" types, meaning that the |
66 | * address of the object (or any of its members) will not escape. |
67 | * Trivially copyable types are location-invariant and users can |
68 | * specialize this trait for other types. |
69 | */ |
70 | template<typename _Tp> |
71 | struct __is_location_invariant |
72 | : is_trivially_copyable<_Tp>::type |
73 | { }; |
74 | |
75 | class _Undefined_class; |
76 | |
77 | union _Nocopy_types |
78 | { |
79 | void* _M_object; |
80 | const void* _M_const_object; |
81 | void (*_M_function_pointer)(); |
82 | void (_Undefined_class::*_M_member_pointer)(); |
83 | }; |
84 | |
85 | union [[gnu::may_alias]] _Any_data |
86 | { |
87 | void* _M_access() { return &_M_pod_data[0]; } |
88 | const void* _M_access() const { return &_M_pod_data[0]; } |
89 | |
90 | template<typename _Tp> |
91 | _Tp& |
92 | _M_access() |
93 | { return *static_cast<_Tp*>(_M_access()); } |
94 | |
95 | template<typename _Tp> |
96 | const _Tp& |
97 | _M_access() const |
98 | { return *static_cast<const _Tp*>(_M_access()); } |
99 | |
100 | _Nocopy_types _M_unused; |
101 | char _M_pod_data[sizeof(_Nocopy_types)]; |
102 | }; |
103 | |
104 | enum _Manager_operation |
105 | { |
106 | __get_type_info, |
107 | __get_functor_ptr, |
108 | __clone_functor, |
109 | __destroy_functor |
110 | }; |
111 | |
112 | template<typename _Signature> |
113 | class function; |
114 | |
115 | /// Base class of all polymorphic function object wrappers. |
116 | class _Function_base |
117 | { |
118 | public: |
119 | static const size_t _M_max_size = sizeof(_Nocopy_types); |
120 | static const size_t _M_max_align = __alignof__(_Nocopy_types); |
121 | |
122 | template<typename _Functor> |
123 | class _Base_manager |
124 | { |
125 | protected: |
126 | static const bool __stored_locally = |
127 | (__is_location_invariant<_Functor>::value |
128 | && sizeof(_Functor) <= _M_max_size |
129 | && __alignof__(_Functor) <= _M_max_align |
130 | && (_M_max_align % __alignof__(_Functor) == 0)); |
131 | |
132 | typedef integral_constant<bool, __stored_locally> _Local_storage; |
133 | |
134 | // Retrieve a pointer to the function object |
135 | static _Functor* |
136 | _M_get_pointer(const _Any_data& __source) |
137 | { |
138 | if _GLIBCXX17_CONSTEXPR (__stored_locally) |
139 | { |
140 | const _Functor& __f = __source._M_access<_Functor>(); |
141 | return const_cast<_Functor*>(std::__addressof(__f)); |
142 | } |
143 | else // have stored a pointer |
144 | return __source._M_access<_Functor*>(); |
145 | } |
146 | |
147 | // Clone a location-invariant function object that fits within |
148 | // an _Any_data structure. |
149 | static void |
150 | _M_clone(_Any_data& __dest, const _Any_data& __source, true_type) |
151 | { |
152 | ::new (__dest._M_access()) _Functor(__source._M_access<_Functor>()); |
153 | } |
154 | |
155 | // Clone a function object that is not location-invariant or |
156 | // that cannot fit into an _Any_data structure. |
157 | static void |
158 | _M_clone(_Any_data& __dest, const _Any_data& __source, false_type) |
159 | { |
160 | __dest._M_access<_Functor*>() = |
161 | new _Functor(*__source._M_access<const _Functor*>()); |
162 | } |
163 | |
164 | // Destroying a location-invariant object may still require |
165 | // destruction. |
166 | static void |
167 | _M_destroy(_Any_data& __victim, true_type) |
168 | { |
169 | __victim._M_access<_Functor>().~_Functor(); |
170 | } |
171 | |
172 | // Destroying an object located on the heap. |
173 | static void |
174 | _M_destroy(_Any_data& __victim, false_type) |
175 | { |
176 | delete __victim._M_access<_Functor*>(); |
177 | } |
178 | |
179 | public: |
180 | static bool |
181 | _M_manager(_Any_data& __dest, const _Any_data& __source, |
182 | _Manager_operation __op) |
183 | { |
184 | switch (__op) |
185 | { |
186 | #if __cpp_rtti199711L |
187 | case __get_type_info: |
188 | __dest._M_access<const type_info*>() = &typeid(_Functor); |
189 | break; |
190 | #endif |
191 | case __get_functor_ptr: |
192 | __dest._M_access<_Functor*>() = _M_get_pointer(__source); |
193 | break; |
194 | |
195 | case __clone_functor: |
196 | _M_clone(__dest, __source, _Local_storage()); |
197 | break; |
198 | |
199 | case __destroy_functor: |
200 | _M_destroy(__dest, _Local_storage()); |
201 | break; |
202 | } |
203 | return false; |
204 | } |
205 | |
206 | static void |
207 | _M_init_functor(_Any_data& __functor, _Functor&& __f) |
208 | { _M_init_functor(__functor, std::move(__f), _Local_storage()); } |
209 | |
210 | template<typename _Signature> |
211 | static bool |
212 | _M_not_empty_function(const function<_Signature>& __f) |
213 | { return static_cast<bool>(__f); } |
214 | |
215 | template<typename _Tp> |
216 | static bool |
217 | _M_not_empty_function(_Tp* __fp) |
218 | { return __fp != nullptr; } |
219 | |
220 | template<typename _Class, typename _Tp> |
221 | static bool |
222 | _M_not_empty_function(_Tp _Class::* __mp) |
223 | { return __mp != nullptr; } |
224 | |
225 | template<typename _Tp> |
226 | static bool |
227 | _M_not_empty_function(const _Tp&) |
228 | { return true; } |
229 | |
230 | private: |
231 | static void |
232 | _M_init_functor(_Any_data& __functor, _Functor&& __f, true_type) |
233 | { ::new (__functor._M_access()) _Functor(std::move(__f)); } |
234 | |
235 | static void |
236 | _M_init_functor(_Any_data& __functor, _Functor&& __f, false_type) |
237 | { __functor._M_access<_Functor*>() = new _Functor(std::move(__f)); } |
238 | }; |
239 | |
240 | _Function_base() : _M_manager(nullptr) { } |
241 | |
242 | ~_Function_base() |
243 | { |
244 | if (_M_manager) |
245 | _M_manager(_M_functor, _M_functor, __destroy_functor); |
246 | } |
247 | |
248 | bool _M_empty() const { return !_M_manager; } |
249 | |
250 | typedef bool (*_Manager_type)(_Any_data&, const _Any_data&, |
251 | _Manager_operation); |
252 | |
253 | _Any_data _M_functor; |
254 | _Manager_type _M_manager; |
255 | }; |
256 | |
257 | template<typename _Signature, typename _Functor> |
258 | class _Function_handler; |
259 | |
260 | template<typename _Res, typename _Functor, typename... _ArgTypes> |
261 | class _Function_handler<_Res(_ArgTypes...), _Functor> |
262 | : public _Function_base::_Base_manager<_Functor> |
263 | { |
264 | typedef _Function_base::_Base_manager<_Functor> _Base; |
265 | |
266 | public: |
267 | static bool |
268 | _M_manager(_Any_data& __dest, const _Any_data& __source, |
269 | _Manager_operation __op) |
270 | { |
271 | switch (__op) |
272 | { |
273 | #if __cpp_rtti199711L |
274 | case __get_type_info: |
275 | __dest._M_access<const type_info*>() = &typeid(_Functor); |
276 | break; |
277 | #endif |
278 | case __get_functor_ptr: |
279 | __dest._M_access<_Functor*>() = _Base::_M_get_pointer(__source); |
280 | break; |
281 | |
282 | default: |
283 | _Base::_M_manager(__dest, __source, __op); |
284 | } |
285 | return false; |
286 | } |
287 | |
288 | static _Res |
289 | _M_invoke(const _Any_data& __functor, _ArgTypes&&... __args) |
290 | { |
291 | return std::__invoke_r<_Res>(*_Base::_M_get_pointer(__functor), |
292 | std::forward<_ArgTypes>(__args)...); |
293 | } |
294 | }; |
295 | |
296 | /** |
297 | * @brief Primary class template for std::function. |
298 | * @ingroup functors |
299 | * |
300 | * Polymorphic function wrapper. |
301 | */ |
302 | template<typename _Res, typename... _ArgTypes> |
303 | class function<_Res(_ArgTypes...)> |
304 | : public _Maybe_unary_or_binary_function<_Res, _ArgTypes...>, |
305 | private _Function_base |
306 | { |
307 | template<typename _Func, |
308 | typename _Res2 = __invoke_result<_Func&, _ArgTypes...>> |
309 | struct _Callable |
310 | : __is_invocable_impl<_Res2, _Res>::type |
311 | { }; |
312 | |
313 | // Used so the return type convertibility checks aren't done when |
314 | // performing overload resolution for copy construction/assignment. |
315 | template<typename _Tp> |
316 | struct _Callable<function, _Tp> : false_type { }; |
317 | |
318 | template<typename _Cond, typename _Tp> |
319 | using _Requires = typename enable_if<_Cond::value, _Tp>::type; |
320 | |
321 | public: |
322 | typedef _Res result_type; |
323 | |
324 | // [3.7.2.1] construct/copy/destroy |
325 | |
326 | /** |
327 | * @brief Default construct creates an empty function call wrapper. |
328 | * @post @c !(bool)*this |
329 | */ |
330 | function() noexcept |
331 | : _Function_base() { } |
332 | |
333 | /** |
334 | * @brief Creates an empty function call wrapper. |
335 | * @post @c !(bool)*this |
336 | */ |
337 | function(nullptr_t) noexcept |
338 | : _Function_base() { } |
339 | |
340 | /** |
341 | * @brief %Function copy constructor. |
342 | * @param __x A %function object with identical call signature. |
343 | * @post @c bool(*this) == bool(__x) |
344 | * |
345 | * The newly-created %function contains a copy of the target of @a |
346 | * __x (if it has one). |
347 | */ |
348 | function(const function& __x); |
349 | |
350 | /** |
351 | * @brief %Function move constructor. |
352 | * @param __x A %function object rvalue with identical call signature. |
353 | * |
354 | * The newly-created %function contains the target of @a __x |
355 | * (if it has one). |
356 | */ |
357 | function(function&& __x) noexcept : _Function_base() |
358 | { |
359 | __x.swap(*this); |
360 | } |
361 | |
362 | /** |
363 | * @brief Builds a %function that targets a copy of the incoming |
364 | * function object. |
365 | * @param __f A %function object that is callable with parameters of |
366 | * type @c T1, @c T2, ..., @c TN and returns a value convertible |
367 | * to @c Res. |
368 | * |
369 | * The newly-created %function object will target a copy of |
370 | * @a __f. If @a __f is @c reference_wrapper<F>, then this function |
371 | * object will contain a reference to the function object @c |
372 | * __f.get(). If @a __f is a NULL function pointer or NULL |
373 | * pointer-to-member, the newly-created object will be empty. |
374 | * |
375 | * If @a __f is a non-NULL function pointer or an object of type @c |
376 | * reference_wrapper<F>, this function will not throw. |
377 | */ |
378 | template<typename _Functor, |
379 | typename = _Requires<__not_<is_same<_Functor, function>>, void>, |
380 | typename = _Requires<_Callable<_Functor>, void>> |
381 | function(_Functor); |
382 | |
383 | /** |
384 | * @brief %Function assignment operator. |
385 | * @param __x A %function with identical call signature. |
386 | * @post @c (bool)*this == (bool)x |
387 | * @returns @c *this |
388 | * |
389 | * The target of @a __x is copied to @c *this. If @a __x has no |
390 | * target, then @c *this will be empty. |
391 | * |
392 | * If @a __x targets a function pointer or a reference to a function |
393 | * object, then this operation will not throw an %exception. |
394 | */ |
395 | function& |
396 | operator=(const function& __x) |
397 | { |
398 | function(__x).swap(*this); |
399 | return *this; |
400 | } |
401 | |
402 | /** |
403 | * @brief %Function move-assignment operator. |
404 | * @param __x A %function rvalue with identical call signature. |
405 | * @returns @c *this |
406 | * |
407 | * The target of @a __x is moved to @c *this. If @a __x has no |
408 | * target, then @c *this will be empty. |
409 | * |
410 | * If @a __x targets a function pointer or a reference to a function |
411 | * object, then this operation will not throw an %exception. |
412 | */ |
413 | function& |
414 | operator=(function&& __x) noexcept |
415 | { |
416 | function(std::move(__x)).swap(*this); |
417 | return *this; |
418 | } |
419 | |
420 | /** |
421 | * @brief %Function assignment to zero. |
422 | * @post @c !(bool)*this |
423 | * @returns @c *this |
424 | * |
425 | * The target of @c *this is deallocated, leaving it empty. |
426 | */ |
427 | function& |
428 | operator=(nullptr_t) noexcept |
429 | { |
430 | if (_M_manager) |
431 | { |
432 | _M_manager(_M_functor, _M_functor, __destroy_functor); |
433 | _M_manager = nullptr; |
434 | _M_invoker = nullptr; |
435 | } |
436 | return *this; |
437 | } |
438 | |
439 | /** |
440 | * @brief %Function assignment to a new target. |
441 | * @param __f A %function object that is callable with parameters of |
442 | * type @c T1, @c T2, ..., @c TN and returns a value convertible |
443 | * to @c Res. |
444 | * @return @c *this |
445 | * |
446 | * This %function object wrapper will target a copy of @a |
447 | * __f. If @a __f is @c reference_wrapper<F>, then this function |
448 | * object will contain a reference to the function object @c |
449 | * __f.get(). If @a __f is a NULL function pointer or NULL |
450 | * pointer-to-member, @c this object will be empty. |
451 | * |
452 | * If @a __f is a non-NULL function pointer or an object of type @c |
453 | * reference_wrapper<F>, this function will not throw. |
454 | */ |
455 | template<typename _Functor> |
456 | _Requires<_Callable<typename decay<_Functor>::type>, function&> |
457 | operator=(_Functor&& __f) |
458 | { |
459 | function(std::forward<_Functor>(__f)).swap(*this); |
460 | return *this; |
461 | } |
462 | |
463 | /// @overload |
464 | template<typename _Functor> |
465 | function& |
466 | operator=(reference_wrapper<_Functor> __f) noexcept |
467 | { |
468 | function(__f).swap(*this); |
469 | return *this; |
470 | } |
471 | |
472 | // [3.7.2.2] function modifiers |
473 | |
474 | /** |
475 | * @brief Swap the targets of two %function objects. |
476 | * @param __x A %function with identical call signature. |
477 | * |
478 | * Swap the targets of @c this function object and @a __f. This |
479 | * function will not throw an %exception. |
480 | */ |
481 | void swap(function& __x) noexcept |
482 | { |
483 | std::swap(_M_functor, __x._M_functor); |
484 | std::swap(_M_manager, __x._M_manager); |
485 | std::swap(_M_invoker, __x._M_invoker); |
486 | } |
487 | |
488 | // [3.7.2.3] function capacity |
489 | |
490 | /** |
491 | * @brief Determine if the %function wrapper has a target. |
492 | * |
493 | * @return @c true when this %function object contains a target, |
494 | * or @c false when it is empty. |
495 | * |
496 | * This function will not throw an %exception. |
497 | */ |
498 | explicit operator bool() const noexcept |
499 | { return !_M_empty(); } |
500 | |
501 | // [3.7.2.4] function invocation |
502 | |
503 | /** |
504 | * @brief Invokes the function targeted by @c *this. |
505 | * @returns the result of the target. |
506 | * @throws bad_function_call when @c !(bool)*this |
507 | * |
508 | * The function call operator invokes the target function object |
509 | * stored by @c this. |
510 | */ |
511 | _Res operator()(_ArgTypes... __args) const; |
512 | |
513 | #if __cpp_rtti199711L |
514 | // [3.7.2.5] function target access |
515 | /** |
516 | * @brief Determine the type of the target of this function object |
517 | * wrapper. |
518 | * |
519 | * @returns the type identifier of the target function object, or |
520 | * @c typeid(void) if @c !(bool)*this. |
521 | * |
522 | * This function will not throw an %exception. |
523 | */ |
524 | const type_info& target_type() const noexcept; |
525 | |
526 | /** |
527 | * @brief Access the stored target function object. |
528 | * |
529 | * @return Returns a pointer to the stored target function object, |
530 | * if @c typeid(_Functor).equals(target_type()); otherwise, a NULL |
531 | * pointer. |
532 | * |
533 | * This function does not throw exceptions. |
534 | * |
535 | * @{ |
536 | */ |
537 | template<typename _Functor> _Functor* target() noexcept; |
538 | |
539 | template<typename _Functor> const _Functor* target() const noexcept; |
540 | // @} |
541 | #endif |
542 | |
543 | private: |
544 | using _Invoker_type = _Res (*)(const _Any_data&, _ArgTypes&&...); |
545 | _Invoker_type _M_invoker; |
546 | }; |
547 | |
548 | #if __cpp_deduction_guides >= 201606 |
549 | template<typename> |
550 | struct __function_guide_helper |
551 | { }; |
552 | |
553 | template<typename _Res, typename _Tp, bool _Nx, typename... _Args> |
554 | struct __function_guide_helper< |
555 | _Res (_Tp::*) (_Args...) noexcept(_Nx) |
556 | > |
557 | { using type = _Res(_Args...); }; |
558 | |
559 | template<typename _Res, typename _Tp, bool _Nx, typename... _Args> |
560 | struct __function_guide_helper< |
561 | _Res (_Tp::*) (_Args...) & noexcept(_Nx) |
562 | > |
563 | { using type = _Res(_Args...); }; |
564 | |
565 | template<typename _Res, typename _Tp, bool _Nx, typename... _Args> |
566 | struct __function_guide_helper< |
567 | _Res (_Tp::*) (_Args...) const noexcept(_Nx) |
568 | > |
569 | { using type = _Res(_Args...); }; |
570 | |
571 | template<typename _Res, typename _Tp, bool _Nx, typename... _Args> |
572 | struct __function_guide_helper< |
573 | _Res (_Tp::*) (_Args...) const & noexcept(_Nx) |
574 | > |
575 | { using type = _Res(_Args...); }; |
576 | |
577 | template<typename _Res, typename... _ArgTypes> |
578 | function(_Res(*)(_ArgTypes...)) -> function<_Res(_ArgTypes...)>; |
579 | |
580 | template<typename _Functor, typename _Signature = typename |
581 | __function_guide_helper<decltype(&_Functor::operator())>::type> |
582 | function(_Functor) -> function<_Signature>; |
583 | #endif |
584 | |
585 | // Out-of-line member definitions. |
586 | template<typename _Res, typename... _ArgTypes> |
587 | function<_Res(_ArgTypes...)>:: |
588 | function(const function& __x) |
589 | : _Function_base() |
590 | { |
591 | if (static_cast<bool>(__x)) |
592 | { |
593 | __x._M_manager(_M_functor, __x._M_functor, __clone_functor); |
594 | _M_invoker = __x._M_invoker; |
595 | _M_manager = __x._M_manager; |
596 | } |
597 | } |
598 | |
599 | template<typename _Res, typename... _ArgTypes> |
600 | template<typename _Functor, typename, typename> |
601 | function<_Res(_ArgTypes...)>:: |
602 | function(_Functor __f) |
603 | : _Function_base() |
604 | { |
605 | typedef _Function_handler<_Res(_ArgTypes...), _Functor> _My_handler; |
606 | |
607 | if (_My_handler::_M_not_empty_function(__f)) |
608 | { |
609 | _My_handler::_M_init_functor(_M_functor, std::move(__f)); |
610 | _M_invoker = &_My_handler::_M_invoke; |
611 | _M_manager = &_My_handler::_M_manager; |
612 | } |
613 | } |
614 | |
615 | template<typename _Res, typename... _ArgTypes> |
616 | _Res |
617 | function<_Res(_ArgTypes...)>:: |
618 | operator()(_ArgTypes... __args) const |
619 | { |
620 | if (_M_empty()) |
621 | __throw_bad_function_call(); |
622 | return _M_invoker(_M_functor, std::forward<_ArgTypes>(__args)...); |
623 | } |
624 | |
625 | #if __cpp_rtti199711L |
626 | template<typename _Res, typename... _ArgTypes> |
627 | const type_info& |
628 | function<_Res(_ArgTypes...)>:: |
629 | target_type() const noexcept |
630 | { |
631 | if (_M_manager) |
632 | { |
633 | _Any_data __typeinfo_result; |
634 | _M_manager(__typeinfo_result, _M_functor, __get_type_info); |
635 | return *__typeinfo_result._M_access<const type_info*>(); |
636 | } |
637 | else |
638 | return typeid(void); |
639 | } |
640 | |
641 | template<typename _Res, typename... _ArgTypes> |
642 | template<typename _Functor> |
643 | _Functor* |
644 | function<_Res(_ArgTypes...)>:: |
645 | target() noexcept |
646 | { |
647 | const function* __const_this = this; |
648 | const _Functor* __func = __const_this->template target<_Functor>(); |
649 | return const_cast<_Functor*>(__func); |
650 | } |
651 | |
652 | template<typename _Res, typename... _ArgTypes> |
653 | template<typename _Functor> |
654 | const _Functor* |
655 | function<_Res(_ArgTypes...)>:: |
656 | target() const noexcept |
657 | { |
658 | if (typeid(_Functor) == target_type() && _M_manager) |
659 | { |
660 | _Any_data __ptr; |
661 | _M_manager(__ptr, _M_functor, __get_functor_ptr); |
662 | return __ptr._M_access<const _Functor*>(); |
663 | } |
664 | else |
665 | return nullptr; |
666 | } |
667 | #endif |
668 | |
669 | // [20.7.15.2.6] null pointer comparisons |
670 | |
671 | /** |
672 | * @brief Compares a polymorphic function object wrapper against 0 |
673 | * (the NULL pointer). |
674 | * @returns @c true if the wrapper has no target, @c false otherwise |
675 | * |
676 | * This function will not throw an %exception. |
677 | */ |
678 | template<typename _Res, typename... _Args> |
679 | inline bool |
680 | operator==(const function<_Res(_Args...)>& __f, nullptr_t) noexcept |
681 | { return !static_cast<bool>(__f); } |
682 | |
683 | #if __cpp_impl_three_way_comparison < 201907L |
684 | /// @overload |
685 | template<typename _Res, typename... _Args> |
686 | inline bool |
687 | operator==(nullptr_t, const function<_Res(_Args...)>& __f) noexcept |
688 | { return !static_cast<bool>(__f); } |
689 | |
690 | /** |
691 | * @brief Compares a polymorphic function object wrapper against 0 |
692 | * (the NULL pointer). |
693 | * @returns @c false if the wrapper has no target, @c true otherwise |
694 | * |
695 | * This function will not throw an %exception. |
696 | */ |
697 | template<typename _Res, typename... _Args> |
698 | inline bool |
699 | operator!=(const function<_Res(_Args...)>& __f, nullptr_t) noexcept |
700 | { return static_cast<bool>(__f); } |
701 | |
702 | /// @overload |
703 | template<typename _Res, typename... _Args> |
704 | inline bool |
705 | operator!=(nullptr_t, const function<_Res(_Args...)>& __f) noexcept |
706 | { return static_cast<bool>(__f); } |
707 | #endif |
708 | |
709 | // [20.7.15.2.7] specialized algorithms |
710 | |
711 | /** |
712 | * @brief Swap the targets of two polymorphic function object wrappers. |
713 | * |
714 | * This function will not throw an %exception. |
715 | */ |
716 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
717 | // 2062. Effect contradictions w/o no-throw guarantee of std::function swaps |
718 | template<typename _Res, typename... _Args> |
719 | inline void |
720 | swap(function<_Res(_Args...)>& __x, function<_Res(_Args...)>& __y) noexcept |
721 | { __x.swap(__y); } |
722 | |
723 | #if __cplusplus201402L >= 201703L |
724 | namespace __detail::__variant |
725 | { |
726 | template<typename> struct _Never_valueless_alt; // see <variant> |
727 | |
728 | // Provide the strong exception-safety guarantee when emplacing a |
729 | // function into a variant. |
730 | template<typename _Signature> |
731 | struct _Never_valueless_alt<std::function<_Signature>> |
732 | : std::true_type |
733 | { }; |
734 | } // namespace __detail::__variant |
735 | #endif // C++17 |
736 | |
737 | _GLIBCXX_END_NAMESPACE_VERSION |
738 | } // namespace std |
739 | |
740 | #endif // C++11 |
741 | #endif // _GLIBCXX_STD_FUNCTION_H |
1 | // Implementation of INVOKE -*- C++ -*- |
2 | |
3 | // Copyright (C) 2016-2020 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file include/bits/invoke.h |
26 | * This is an internal header file, included by other library headers. |
27 | * Do not attempt to use it directly. @headername{functional} |
28 | */ |
29 | |
30 | #ifndef _GLIBCXX_INVOKE_H1 |
31 | #define _GLIBCXX_INVOKE_H1 1 |
32 | |
33 | #pragma GCC system_header |
34 | |
35 | #if __cplusplus201402L < 201103L |
36 | # include <bits/c++0x_warning.h> |
37 | #else |
38 | |
39 | #include <type_traits> |
40 | |
41 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
42 | { |
43 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
44 | |
45 | /** |
46 | * @addtogroup utilities |
47 | * @{ |
48 | */ |
49 | |
50 | // Used by __invoke_impl instead of std::forward<_Tp> so that a |
51 | // reference_wrapper is converted to an lvalue-reference. |
52 | template<typename _Tp, typename _Up = typename __inv_unwrap<_Tp>::type> |
53 | constexpr _Up&& |
54 | __invfwd(typename remove_reference<_Tp>::type& __t) noexcept |
55 | { return static_cast<_Up&&>(__t); } |
56 | |
57 | template<typename _Res, typename _Fn, typename... _Args> |
58 | constexpr _Res |
59 | __invoke_impl(__invoke_other, _Fn&& __f, _Args&&... __args) |
60 | { return std::forward<_Fn>(__f)(std::forward<_Args>(__args)...); } |
61 | |
62 | template<typename _Res, typename _MemFun, typename _Tp, typename... _Args> |
63 | constexpr _Res |
64 | __invoke_impl(__invoke_memfun_ref, _MemFun&& __f, _Tp&& __t, |
65 | _Args&&... __args) |
66 | { return (__invfwd<_Tp>(__t).*__f)(std::forward<_Args>(__args)...); } |
67 | |
68 | template<typename _Res, typename _MemFun, typename _Tp, typename... _Args> |
69 | constexpr _Res |
70 | __invoke_impl(__invoke_memfun_deref, _MemFun&& __f, _Tp&& __t, |
71 | _Args&&... __args) |
72 | { |
73 | return ((*std::forward<_Tp>(__t)).*__f)(std::forward<_Args>(__args)...); |
74 | } |
75 | |
76 | template<typename _Res, typename _MemPtr, typename _Tp> |
77 | constexpr _Res |
78 | __invoke_impl(__invoke_memobj_ref, _MemPtr&& __f, _Tp&& __t) |
79 | { return __invfwd<_Tp>(__t).*__f; } |
80 | |
81 | template<typename _Res, typename _MemPtr, typename _Tp> |
82 | constexpr _Res |
83 | __invoke_impl(__invoke_memobj_deref, _MemPtr&& __f, _Tp&& __t) |
84 | { return (*std::forward<_Tp>(__t)).*__f; } |
85 | |
86 | /// Invoke a callable object. |
87 | template<typename _Callable, typename... _Args> |
88 | constexpr typename __invoke_result<_Callable, _Args...>::type |
89 | __invoke(_Callable&& __fn, _Args&&... __args) |
90 | noexcept(__is_nothrow_invocable<_Callable, _Args...>::value) |
91 | { |
92 | using __result = __invoke_result<_Callable, _Args...>; |
93 | using __type = typename __result::type; |
94 | using __tag = typename __result::__invoke_type; |
95 | return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), |
96 | std::forward<_Args>(__args)...); |
97 | } |
98 | |
99 | #if __cplusplus201402L >= 201703L |
100 | // INVOKE<R>: Invoke a callable object and convert the result to R. |
101 | template<typename _Res, typename _Callable, typename... _Args> |
102 | constexpr enable_if_t<is_invocable_r_v<_Res, _Callable, _Args...>, _Res> |
103 | __invoke_r(_Callable&& __fn, _Args&&... __args) |
104 | noexcept(is_nothrow_invocable_r_v<_Res, _Callable, _Args...>) |
105 | { |
106 | using __result = __invoke_result<_Callable, _Args...>; |
107 | using __type = typename __result::type; |
108 | using __tag = typename __result::__invoke_type; |
109 | if constexpr (is_void_v<_Res>) |
110 | std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), |
111 | std::forward<_Args>(__args)...); |
112 | else |
113 | return std::__invoke_impl<__type>(__tag{}, |
114 | std::forward<_Callable>(__fn), |
115 | std::forward<_Args>(__args)...); |
116 | } |
117 | #else // C++11 |
118 | template<typename _Res, typename _Callable, typename... _Args> |
119 | using __can_invoke_as_void = __enable_if_t< |
120 | __and_<is_void<_Res>, __is_invocable<_Callable, _Args...>>::value, |
121 | _Res |
122 | >; |
123 | |
124 | template<typename _Res, typename _Callable, typename... _Args> |
125 | using __can_invoke_as_nonvoid = __enable_if_t< |
126 | __and_<__not_<is_void<_Res>>, |
127 | is_convertible<typename __invoke_result<_Callable, _Args...>::type, |
128 | _Res> |
129 | >::value, |
130 | _Res |
131 | >; |
132 | |
133 | // INVOKE<R>: Invoke a callable object and convert the result to R. |
134 | template<typename _Res, typename _Callable, typename... _Args> |
135 | constexpr __can_invoke_as_nonvoid<_Res, _Callable, _Args...> |
136 | __invoke_r(_Callable&& __fn, _Args&&... __args) |
137 | { |
138 | using __result = __invoke_result<_Callable, _Args...>; |
139 | using __type = typename __result::type; |
140 | using __tag = typename __result::__invoke_type; |
141 | return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), |
142 | std::forward<_Args>(__args)...); |
143 | } |
144 | |
145 | // INVOKE<R> when R is cv void |
146 | template<typename _Res, typename _Callable, typename... _Args> |
147 | _GLIBCXX14_CONSTEXPRconstexpr __can_invoke_as_void<_Res, _Callable, _Args...> |
148 | __invoke_r(_Callable&& __fn, _Args&&... __args) |
149 | { |
150 | using __result = __invoke_result<_Callable, _Args...>; |
151 | using __type = typename __result::type; |
152 | using __tag = typename __result::__invoke_type; |
153 | std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), |
154 | std::forward<_Args>(__args)...); |
155 | } |
156 | #endif // C++11 |
157 | |
158 | _GLIBCXX_END_NAMESPACE_VERSION |
159 | } // namespace std |
160 | |
161 | #endif // C++11 |
162 | |
163 | #endif // _GLIBCXX_INVOKE_H |
1 | // unique_ptr implementation -*- C++ -*- |
2 | |
3 | // Copyright (C) 2008-2020 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file bits/unique_ptr.h |
26 | * This is an internal header file, included by other library headers. |
27 | * Do not attempt to use it directly. @headername{memory} |
28 | */ |
29 | |
30 | #ifndef _UNIQUE_PTR_H1 |
31 | #define _UNIQUE_PTR_H1 1 |
32 | |
33 | #include <bits/c++config.h> |
34 | #include <debug/assertions.h> |
35 | #include <type_traits> |
36 | #include <utility> |
37 | #include <tuple> |
38 | #include <bits/stl_function.h> |
39 | #include <bits/functional_hash.h> |
40 | #if __cplusplus201402L > 201703L |
41 | # include <compare> |
42 | # include <ostream> |
43 | #endif |
44 | |
45 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
46 | { |
47 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
48 | |
49 | /** |
50 | * @addtogroup pointer_abstractions |
51 | * @{ |
52 | */ |
53 | |
54 | #if _GLIBCXX_USE_DEPRECATED1 |
55 | #pragma GCC diagnostic push |
56 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
57 | template<typename> class auto_ptr; |
58 | #pragma GCC diagnostic pop |
59 | #endif |
60 | |
61 | /// Primary template of default_delete, used by unique_ptr for single objects |
62 | template<typename _Tp> |
63 | struct default_delete |
64 | { |
65 | /// Default constructor |
66 | constexpr default_delete() noexcept = default; |
67 | |
68 | /** @brief Converting constructor. |
69 | * |
70 | * Allows conversion from a deleter for objects of another type, `_Up`, |
71 | * only if `_Up*` is convertible to `_Tp*`. |
72 | */ |
73 | template<typename _Up, |
74 | typename = _Require<is_convertible<_Up*, _Tp*>>> |
75 | default_delete(const default_delete<_Up>&) noexcept { } |
76 | |
77 | /// Calls `delete __ptr` |
78 | void |
79 | operator()(_Tp* __ptr) const |
80 | { |
81 | static_assert(!is_void<_Tp>::value, |
82 | "can't delete pointer to incomplete type"); |
83 | static_assert(sizeof(_Tp)>0, |
84 | "can't delete pointer to incomplete type"); |
85 | delete __ptr; |
86 | } |
87 | }; |
88 | |
89 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
90 | // DR 740 - omit specialization for array objects with a compile time length |
91 | |
92 | /// Specialization of default_delete for arrays, used by `unique_ptr<T[]>` |
93 | template<typename _Tp> |
94 | struct default_delete<_Tp[]> |
95 | { |
96 | public: |
97 | /// Default constructor |
98 | constexpr default_delete() noexcept = default; |
99 | |
100 | /** @brief Converting constructor. |
101 | * |
102 | * Allows conversion from a deleter for arrays of another type, such as |
103 | * a const-qualified version of `_Tp`. |
104 | * |
105 | * Conversions from types derived from `_Tp` are not allowed because |
106 | * it is undefined to `delete[]` an array of derived types through a |
107 | * pointer to the base type. |
108 | */ |
109 | template<typename _Up, |
110 | typename = _Require<is_convertible<_Up(*)[], _Tp(*)[]>>> |
111 | default_delete(const default_delete<_Up[]>&) noexcept { } |
112 | |
113 | /// Calls `delete[] __ptr` |
114 | template<typename _Up> |
115 | typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type |
116 | operator()(_Up* __ptr) const |
117 | { |
118 | static_assert(sizeof(_Tp)>0, |
119 | "can't delete pointer to incomplete type"); |
120 | delete [] __ptr; |
121 | } |
122 | }; |
123 | |
124 | /// @cond undocumented |
125 | |
126 | // Manages the pointer and deleter of a unique_ptr |
127 | template <typename _Tp, typename _Dp> |
128 | class __uniq_ptr_impl |
129 | { |
130 | template <typename _Up, typename _Ep, typename = void> |
131 | struct _Ptr |
132 | { |
133 | using type = _Up*; |
134 | }; |
135 | |
136 | template <typename _Up, typename _Ep> |
137 | struct |
138 | _Ptr<_Up, _Ep, __void_t<typename remove_reference<_Ep>::type::pointer>> |
139 | { |
140 | using type = typename remove_reference<_Ep>::type::pointer; |
141 | }; |
142 | |
143 | public: |
144 | using _DeleterConstraint = enable_if< |
145 | __and_<__not_<is_pointer<_Dp>>, |
146 | is_default_constructible<_Dp>>::value>; |
147 | |
148 | using pointer = typename _Ptr<_Tp, _Dp>::type; |
149 | |
150 | static_assert( !is_rvalue_reference<_Dp>::value, |
151 | "unique_ptr's deleter type must be a function object type" |
152 | " or an lvalue reference type" ); |
153 | |
154 | __uniq_ptr_impl() = default; |
155 | __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; } |
156 | |
157 | template<typename _Del> |
158 | __uniq_ptr_impl(pointer __p, _Del&& __d) |
159 | : _M_t(__p, std::forward<_Del>(__d)) { } |
160 | |
161 | __uniq_ptr_impl(__uniq_ptr_impl&& __u) noexcept |
162 | : _M_t(std::move(__u._M_t)) |
163 | { __u._M_ptr() = nullptr; } |
164 | |
165 | __uniq_ptr_impl& operator=(__uniq_ptr_impl&& __u) noexcept |
166 | { |
167 | reset(__u.release()); |
168 | _M_deleter() = std::forward<_Dp>(__u._M_deleter()); |
169 | return *this; |
170 | } |
171 | |
172 | pointer& _M_ptr() { return std::get<0>(_M_t); } |
173 | pointer _M_ptr() const { return std::get<0>(_M_t); } |
174 | _Dp& _M_deleter() { return std::get<1>(_M_t); } |
175 | const _Dp& _M_deleter() const { return std::get<1>(_M_t); } |
176 | |
177 | void reset(pointer __p) noexcept |
178 | { |
179 | const pointer __old_p = _M_ptr(); |
180 | _M_ptr() = __p; |
181 | if (__old_p) |
182 | _M_deleter()(__old_p); |
183 | } |
184 | |
185 | pointer release() noexcept |
186 | { |
187 | pointer __p = _M_ptr(); |
188 | _M_ptr() = nullptr; |
189 | return __p; |
190 | } |
191 | |
192 | void |
193 | swap(__uniq_ptr_impl& __rhs) noexcept |
194 | { |
195 | using std::swap; |
196 | swap(this->_M_ptr(), __rhs._M_ptr()); |
197 | swap(this->_M_deleter(), __rhs._M_deleter()); |
198 | } |
199 | |
200 | private: |
201 | tuple<pointer, _Dp> _M_t; |
202 | }; |
203 | |
204 | // Defines move construction + assignment as either defaulted or deleted. |
205 | template <typename _Tp, typename _Dp, |
206 | bool = is_move_constructible<_Dp>::value, |
207 | bool = is_move_assignable<_Dp>::value> |
208 | struct __uniq_ptr_data : __uniq_ptr_impl<_Tp, _Dp> |
209 | { |
210 | using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl; |
211 | __uniq_ptr_data(__uniq_ptr_data&&) = default; |
212 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default; |
213 | }; |
214 | |
215 | template <typename _Tp, typename _Dp> |
216 | struct __uniq_ptr_data<_Tp, _Dp, true, false> : __uniq_ptr_impl<_Tp, _Dp> |
217 | { |
218 | using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl; |
219 | __uniq_ptr_data(__uniq_ptr_data&&) = default; |
220 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete; |
221 | }; |
222 | |
223 | template <typename _Tp, typename _Dp> |
224 | struct __uniq_ptr_data<_Tp, _Dp, false, true> : __uniq_ptr_impl<_Tp, _Dp> |
225 | { |
226 | using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl; |
227 | __uniq_ptr_data(__uniq_ptr_data&&) = delete; |
228 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default; |
229 | }; |
230 | |
231 | template <typename _Tp, typename _Dp> |
232 | struct __uniq_ptr_data<_Tp, _Dp, false, false> : __uniq_ptr_impl<_Tp, _Dp> |
233 | { |
234 | using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl; |
235 | __uniq_ptr_data(__uniq_ptr_data&&) = delete; |
236 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete; |
237 | }; |
238 | /// @endcond |
239 | |
240 | /// 20.7.1.2 unique_ptr for single objects. |
241 | template <typename _Tp, typename _Dp = default_delete<_Tp>> |
242 | class unique_ptr |
243 | { |
244 | template <typename _Up> |
245 | using _DeleterConstraint = |
246 | typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type; |
247 | |
248 | __uniq_ptr_data<_Tp, _Dp> _M_t; |
249 | |
250 | public: |
251 | using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer; |
252 | using element_type = _Tp; |
253 | using deleter_type = _Dp; |
254 | |
255 | private: |
256 | // helper template for detecting a safe conversion from another |
257 | // unique_ptr |
258 | template<typename _Up, typename _Ep> |
259 | using __safe_conversion_up = __and_< |
260 | is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>, |
261 | __not_<is_array<_Up>> |
262 | >; |
263 | |
264 | public: |
265 | // Constructors. |
266 | |
267 | /// Default constructor, creates a unique_ptr that owns nothing. |
268 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> |
269 | constexpr unique_ptr() noexcept |
270 | : _M_t() |
271 | { } |
272 | |
273 | /** Takes ownership of a pointer. |
274 | * |
275 | * @param __p A pointer to an object of @c element_type |
276 | * |
277 | * The deleter will be value-initialized. |
278 | */ |
279 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> |
280 | explicit |
281 | unique_ptr(pointer __p) noexcept |
282 | : _M_t(__p) |
283 | { } |
284 | |
285 | /** Takes ownership of a pointer. |
286 | * |
287 | * @param __p A pointer to an object of @c element_type |
288 | * @param __d A reference to a deleter. |
289 | * |
290 | * The deleter will be initialized with @p __d |
291 | */ |
292 | template<typename _Del = deleter_type, |
293 | typename = _Require<is_copy_constructible<_Del>>> |
294 | unique_ptr(pointer __p, const deleter_type& __d) noexcept |
295 | : _M_t(__p, __d) { } |
296 | |
297 | /** Takes ownership of a pointer. |
298 | * |
299 | * @param __p A pointer to an object of @c element_type |
300 | * @param __d An rvalue reference to a (non-reference) deleter. |
301 | * |
302 | * The deleter will be initialized with @p std::move(__d) |
303 | */ |
304 | template<typename _Del = deleter_type, |
305 | typename = _Require<is_move_constructible<_Del>>> |
306 | unique_ptr(pointer __p, |
307 | __enable_if_t<!is_lvalue_reference<_Del>::value, |
308 | _Del&&> __d) noexcept |
309 | : _M_t(__p, std::move(__d)) |
310 | { } |
311 | |
312 | template<typename _Del = deleter_type, |
313 | typename _DelUnref = typename remove_reference<_Del>::type> |
314 | unique_ptr(pointer, |
315 | __enable_if_t<is_lvalue_reference<_Del>::value, |
316 | _DelUnref&&>) = delete; |
317 | |
318 | /// Creates a unique_ptr that owns nothing. |
319 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> |
320 | constexpr unique_ptr(nullptr_t) noexcept |
321 | : _M_t() |
322 | { } |
323 | |
324 | // Move constructors. |
325 | |
326 | /// Move constructor. |
327 | unique_ptr(unique_ptr&&) = default; |
328 | |
329 | /** @brief Converting constructor from another type |
330 | * |
331 | * Requires that the pointer owned by @p __u is convertible to the |
332 | * type of pointer owned by this object, @p __u does not own an array, |
333 | * and @p __u has a compatible deleter type. |
334 | */ |
335 | template<typename _Up, typename _Ep, typename = _Require< |
336 | __safe_conversion_up<_Up, _Ep>, |
337 | typename conditional<is_reference<_Dp>::value, |
338 | is_same<_Ep, _Dp>, |
339 | is_convertible<_Ep, _Dp>>::type>> |
340 | unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept |
341 | : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) |
342 | { } |
343 | |
344 | #if _GLIBCXX_USE_DEPRECATED1 |
345 | #pragma GCC diagnostic push |
346 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
347 | /// Converting constructor from @c auto_ptr |
348 | template<typename _Up, typename = _Require< |
349 | is_convertible<_Up*, _Tp*>, is_same<_Dp, default_delete<_Tp>>>> |
350 | unique_ptr(auto_ptr<_Up>&& __u) noexcept; |
351 | #pragma GCC diagnostic pop |
352 | #endif |
353 | |
354 | /// Destructor, invokes the deleter if the stored pointer is not null. |
355 | ~unique_ptr() noexcept |
356 | { |
357 | static_assert(__is_invocable<deleter_type&, pointer>::value, |
358 | "unique_ptr's deleter must be invocable with a pointer"); |
359 | auto& __ptr = _M_t._M_ptr(); |
360 | if (__ptr != nullptr) |
361 | get_deleter()(std::move(__ptr)); |
362 | __ptr = pointer(); |
363 | } |
364 | |
365 | // Assignment. |
366 | |
367 | /** @brief Move assignment operator. |
368 | * |
369 | * Invokes the deleter if this object owns a pointer. |
370 | */ |
371 | unique_ptr& operator=(unique_ptr&&) = default; |
372 | |
373 | /** @brief Assignment from another type. |
374 | * |
375 | * @param __u The object to transfer ownership from, which owns a |
376 | * convertible pointer to a non-array object. |
377 | * |
378 | * Invokes the deleter if this object owns a pointer. |
379 | */ |
380 | template<typename _Up, typename _Ep> |
381 | typename enable_if< __and_< |
382 | __safe_conversion_up<_Up, _Ep>, |
383 | is_assignable<deleter_type&, _Ep&&> |
384 | >::value, |
385 | unique_ptr&>::type |
386 | operator=(unique_ptr<_Up, _Ep>&& __u) noexcept |
387 | { |
388 | reset(__u.release()); |
389 | get_deleter() = std::forward<_Ep>(__u.get_deleter()); |
390 | return *this; |
391 | } |
392 | |
393 | /// Reset the %unique_ptr to empty, invoking the deleter if necessary. |
394 | unique_ptr& |
395 | operator=(nullptr_t) noexcept |
396 | { |
397 | reset(); |
398 | return *this; |
399 | } |
400 | |
401 | // Observers. |
402 | |
403 | /// Dereference the stored pointer. |
404 | typename add_lvalue_reference<element_type>::type |
405 | operator*() const |
406 | { |
407 | __glibcxx_assert(get() != pointer()); |
408 | return *get(); |
409 | } |
410 | |
411 | /// Return the stored pointer. |
412 | pointer |
413 | operator->() const noexcept |
414 | { |
415 | _GLIBCXX_DEBUG_PEDASSERT(get() != pointer()); |
416 | return get(); |
417 | } |
418 | |
419 | /// Return the stored pointer. |
420 | pointer |
421 | get() const noexcept |
422 | { return _M_t._M_ptr(); } |
423 | |
424 | /// Return a reference to the stored deleter. |
425 | deleter_type& |
426 | get_deleter() noexcept |
427 | { return _M_t._M_deleter(); } |
428 | |
429 | /// Return a reference to the stored deleter. |
430 | const deleter_type& |
431 | get_deleter() const noexcept |
432 | { return _M_t._M_deleter(); } |
433 | |
434 | /// Return @c true if the stored pointer is not null. |
435 | explicit operator bool() const noexcept |
436 | { return get() == pointer() ? false : true; } |
437 | |
438 | // Modifiers. |
439 | |
440 | /// Release ownership of any stored pointer. |
441 | pointer |
442 | release() noexcept |
443 | { return _M_t.release(); } |
444 | |
445 | /** @brief Replace the stored pointer. |
446 | * |
447 | * @param __p The new pointer to store. |
448 | * |
449 | * The deleter will be invoked if a pointer is already owned. |
450 | */ |
451 | void |
452 | reset(pointer __p = pointer()) noexcept |
453 | { |
454 | static_assert(__is_invocable<deleter_type&, pointer>::value, |
455 | "unique_ptr's deleter must be invocable with a pointer"); |
456 | _M_t.reset(std::move(__p)); |
457 | } |
458 | |
459 | /// Exchange the pointer and deleter with another object. |
460 | void |
461 | swap(unique_ptr& __u) noexcept |
462 | { |
463 | static_assert(__is_swappable<_Dp>::value, "deleter must be swappable"); |
464 | _M_t.swap(__u._M_t); |
465 | } |
466 | |
467 | // Disable copy from lvalue. |
468 | unique_ptr(const unique_ptr&) = delete; |
469 | unique_ptr& operator=(const unique_ptr&) = delete; |
470 | }; |
471 | |
472 | /// 20.7.1.3 unique_ptr for array objects with a runtime length |
473 | // [unique.ptr.runtime] |
474 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
475 | // DR 740 - omit specialization for array objects with a compile time length |
476 | template<typename _Tp, typename _Dp> |
477 | class unique_ptr<_Tp[], _Dp> |
478 | { |
479 | template <typename _Up> |
480 | using _DeleterConstraint = |
481 | typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type; |
482 | |
483 | __uniq_ptr_data<_Tp, _Dp> _M_t; |
484 | |
485 | template<typename _Up> |
486 | using __remove_cv = typename remove_cv<_Up>::type; |
487 | |
488 | // like is_base_of<_Tp, _Up> but false if unqualified types are the same |
489 | template<typename _Up> |
490 | using __is_derived_Tp |
491 | = __and_< is_base_of<_Tp, _Up>, |
492 | __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >; |
493 | |
494 | public: |
495 | using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer; |
496 | using element_type = _Tp; |
497 | using deleter_type = _Dp; |
498 | |
499 | // helper template for detecting a safe conversion from another |
500 | // unique_ptr |
501 | template<typename _Up, typename _Ep, |
502 | typename _UPtr = unique_ptr<_Up, _Ep>, |
503 | typename _UP_pointer = typename _UPtr::pointer, |
504 | typename _UP_element_type = typename _UPtr::element_type> |
505 | using __safe_conversion_up = __and_< |
506 | is_array<_Up>, |
507 | is_same<pointer, element_type*>, |
508 | is_same<_UP_pointer, _UP_element_type*>, |
509 | is_convertible<_UP_element_type(*)[], element_type(*)[]> |
510 | >; |
511 | |
512 | // helper template for detecting a safe conversion from a raw pointer |
513 | template<typename _Up> |
514 | using __safe_conversion_raw = __and_< |
515 | __or_<__or_<is_same<_Up, pointer>, |
516 | is_same<_Up, nullptr_t>>, |
517 | __and_<is_pointer<_Up>, |
518 | is_same<pointer, element_type*>, |
519 | is_convertible< |
520 | typename remove_pointer<_Up>::type(*)[], |
521 | element_type(*)[]> |
522 | > |
523 | > |
524 | >; |
525 | |
526 | // Constructors. |
527 | |
528 | /// Default constructor, creates a unique_ptr that owns nothing. |
529 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> |
530 | constexpr unique_ptr() noexcept |
531 | : _M_t() |
532 | { } |
533 | |
534 | /** Takes ownership of a pointer. |
535 | * |
536 | * @param __p A pointer to an array of a type safely convertible |
537 | * to an array of @c element_type |
538 | * |
539 | * The deleter will be value-initialized. |
540 | */ |
541 | template<typename _Up, |
542 | typename _Vp = _Dp, |
543 | typename = _DeleterConstraint<_Vp>, |
544 | typename = typename enable_if< |
545 | __safe_conversion_raw<_Up>::value, bool>::type> |
546 | explicit |
547 | unique_ptr(_Up __p) noexcept |
548 | : _M_t(__p) |
549 | { } |
550 | |
551 | /** Takes ownership of a pointer. |
552 | * |
553 | * @param __p A pointer to an array of a type safely convertible |
554 | * to an array of @c element_type |
555 | * @param __d A reference to a deleter. |
556 | * |
557 | * The deleter will be initialized with @p __d |
558 | */ |
559 | template<typename _Up, typename _Del = deleter_type, |
560 | typename = _Require<__safe_conversion_raw<_Up>, |
561 | is_copy_constructible<_Del>>> |
562 | unique_ptr(_Up __p, const deleter_type& __d) noexcept |
563 | : _M_t(__p, __d) { } |
564 | |
565 | /** Takes ownership of a pointer. |
566 | * |
567 | * @param __p A pointer to an array of a type safely convertible |
568 | * to an array of @c element_type |
569 | * @param __d A reference to a deleter. |
570 | * |
571 | * The deleter will be initialized with @p std::move(__d) |
572 | */ |
573 | template<typename _Up, typename _Del = deleter_type, |
574 | typename = _Require<__safe_conversion_raw<_Up>, |
575 | is_move_constructible<_Del>>> |
576 | unique_ptr(_Up __p, |
577 | __enable_if_t<!is_lvalue_reference<_Del>::value, |
578 | _Del&&> __d) noexcept |
579 | : _M_t(std::move(__p), std::move(__d)) |
580 | { } |
581 | |
582 | template<typename _Up, typename _Del = deleter_type, |
583 | typename _DelUnref = typename remove_reference<_Del>::type, |
584 | typename = _Require<__safe_conversion_raw<_Up>>> |
585 | unique_ptr(_Up, |
586 | __enable_if_t<is_lvalue_reference<_Del>::value, |
587 | _DelUnref&&>) = delete; |
588 | |
589 | /// Move constructor. |
590 | unique_ptr(unique_ptr&&) = default; |
591 | |
592 | /// Creates a unique_ptr that owns nothing. |
593 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> |
594 | constexpr unique_ptr(nullptr_t) noexcept |
595 | : _M_t() |
596 | { } |
597 | |
598 | template<typename _Up, typename _Ep, typename = _Require< |
599 | __safe_conversion_up<_Up, _Ep>, |
600 | typename conditional<is_reference<_Dp>::value, |
601 | is_same<_Ep, _Dp>, |
602 | is_convertible<_Ep, _Dp>>::type>> |
603 | unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept |
604 | : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) |
605 | { } |
606 | |
607 | /// Destructor, invokes the deleter if the stored pointer is not null. |
608 | ~unique_ptr() |
609 | { |
610 | auto& __ptr = _M_t._M_ptr(); |
611 | if (__ptr != nullptr) |
612 | get_deleter()(__ptr); |
613 | __ptr = pointer(); |
614 | } |
615 | |
616 | // Assignment. |
617 | |
618 | /** @brief Move assignment operator. |
619 | * |
620 | * Invokes the deleter if this object owns a pointer. |
621 | */ |
622 | unique_ptr& |
623 | operator=(unique_ptr&&) = default; |
624 | |
625 | /** @brief Assignment from another type. |
626 | * |
627 | * @param __u The object to transfer ownership from, which owns a |
628 | * convertible pointer to an array object. |
629 | * |
630 | * Invokes the deleter if this object owns a pointer. |
631 | */ |
632 | template<typename _Up, typename _Ep> |
633 | typename |
634 | enable_if<__and_<__safe_conversion_up<_Up, _Ep>, |
635 | is_assignable<deleter_type&, _Ep&&> |
636 | >::value, |
637 | unique_ptr&>::type |
638 | operator=(unique_ptr<_Up, _Ep>&& __u) noexcept |
639 | { |
640 | reset(__u.release()); |
641 | get_deleter() = std::forward<_Ep>(__u.get_deleter()); |
642 | return *this; |
643 | } |
644 | |
645 | /// Reset the %unique_ptr to empty, invoking the deleter if necessary. |
646 | unique_ptr& |
647 | operator=(nullptr_t) noexcept |
648 | { |
649 | reset(); |
650 | return *this; |
651 | } |
652 | |
653 | // Observers. |
654 | |
655 | /// Access an element of owned array. |
656 | typename std::add_lvalue_reference<element_type>::type |
657 | operator[](size_t __i) const |
658 | { |
659 | __glibcxx_assert(get() != pointer()); |
660 | return get()[__i]; |
661 | } |
662 | |
663 | /// Return the stored pointer. |
664 | pointer |
665 | get() const noexcept |
666 | { return _M_t._M_ptr(); } |
667 | |
668 | /// Return a reference to the stored deleter. |
669 | deleter_type& |
670 | get_deleter() noexcept |
671 | { return _M_t._M_deleter(); } |
672 | |
673 | /// Return a reference to the stored deleter. |
674 | const deleter_type& |
675 | get_deleter() const noexcept |
676 | { return _M_t._M_deleter(); } |
677 | |
678 | /// Return @c true if the stored pointer is not null. |
679 | explicit operator bool() const noexcept |
680 | { return get() == pointer() ? false : true; } |
681 | |
682 | // Modifiers. |
683 | |
684 | /// Release ownership of any stored pointer. |
685 | pointer |
686 | release() noexcept |
687 | { return _M_t.release(); } |
688 | |
689 | /** @brief Replace the stored pointer. |
690 | * |
691 | * @param __p The new pointer to store. |
692 | * |
693 | * The deleter will be invoked if a pointer is already owned. |
694 | */ |
695 | template <typename _Up, |
696 | typename = _Require< |
697 | __or_<is_same<_Up, pointer>, |
698 | __and_<is_same<pointer, element_type*>, |
699 | is_pointer<_Up>, |
700 | is_convertible< |
701 | typename remove_pointer<_Up>::type(*)[], |
702 | element_type(*)[] |
703 | > |
704 | > |
705 | > |
706 | >> |
707 | void |
708 | reset(_Up __p) noexcept |
709 | { _M_t.reset(std::move(__p)); } |
710 | |
711 | void reset(nullptr_t = nullptr) noexcept |
712 | { reset(pointer()); } |
713 | |
714 | /// Exchange the pointer and deleter with another object. |
715 | void |
716 | swap(unique_ptr& __u) noexcept |
717 | { |
718 | static_assert(__is_swappable<_Dp>::value, "deleter must be swappable"); |
719 | _M_t.swap(__u._M_t); |
720 | } |
721 | |
722 | // Disable copy from lvalue. |
723 | unique_ptr(const unique_ptr&) = delete; |
724 | unique_ptr& operator=(const unique_ptr&) = delete; |
725 | }; |
726 | |
727 | /// @relates unique_ptr @{ |
728 | |
729 | /// Swap overload for unique_ptr |
730 | template<typename _Tp, typename _Dp> |
731 | inline |
732 | #if __cplusplus201402L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 |
733 | // Constrained free swap overload, see p0185r1 |
734 | typename enable_if<__is_swappable<_Dp>::value>::type |
735 | #else |
736 | void |
737 | #endif |
738 | swap(unique_ptr<_Tp, _Dp>& __x, |
739 | unique_ptr<_Tp, _Dp>& __y) noexcept |
740 | { __x.swap(__y); } |
741 | |
742 | #if __cplusplus201402L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 |
743 | template<typename _Tp, typename _Dp> |
744 | typename enable_if<!__is_swappable<_Dp>::value>::type |
745 | swap(unique_ptr<_Tp, _Dp>&, |
746 | unique_ptr<_Tp, _Dp>&) = delete; |
747 | #endif |
748 | |
749 | /// Equality operator for unique_ptr objects, compares the owned pointers |
750 | template<typename _Tp, typename _Dp, |
751 | typename _Up, typename _Ep> |
752 | _GLIBCXX_NODISCARD inline bool |
753 | operator==(const unique_ptr<_Tp, _Dp>& __x, |
754 | const unique_ptr<_Up, _Ep>& __y) |
755 | { return __x.get() == __y.get(); } |
756 | |
757 | /// unique_ptr comparison with nullptr |
758 | template<typename _Tp, typename _Dp> |
759 | _GLIBCXX_NODISCARD inline bool |
760 | operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept |
761 | { return !__x; } |
762 | |
763 | #ifndef __cpp_lib_three_way_comparison |
764 | /// unique_ptr comparison with nullptr |
765 | template<typename _Tp, typename _Dp> |
766 | _GLIBCXX_NODISCARD inline bool |
767 | operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept |
768 | { return !__x; } |
769 | |
770 | /// Inequality operator for unique_ptr objects, compares the owned pointers |
771 | template<typename _Tp, typename _Dp, |
772 | typename _Up, typename _Ep> |
773 | _GLIBCXX_NODISCARD inline bool |
774 | operator!=(const unique_ptr<_Tp, _Dp>& __x, |
775 | const unique_ptr<_Up, _Ep>& __y) |
776 | { return __x.get() != __y.get(); } |
777 | |
778 | /// unique_ptr comparison with nullptr |
779 | template<typename _Tp, typename _Dp> |
780 | _GLIBCXX_NODISCARD inline bool |
781 | operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept |
782 | { return (bool)__x; } |
783 | |
784 | /// unique_ptr comparison with nullptr |
785 | template<typename _Tp, typename _Dp> |
786 | _GLIBCXX_NODISCARD inline bool |
787 | operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept |
788 | { return (bool)__x; } |
789 | #endif // three way comparison |
790 | |
791 | /// Relational operator for unique_ptr objects, compares the owned pointers |
792 | template<typename _Tp, typename _Dp, |
793 | typename _Up, typename _Ep> |
794 | _GLIBCXX_NODISCARD inline bool |
795 | operator<(const unique_ptr<_Tp, _Dp>& __x, |
796 | const unique_ptr<_Up, _Ep>& __y) |
797 | { |
798 | typedef typename |
799 | std::common_type<typename unique_ptr<_Tp, _Dp>::pointer, |
800 | typename unique_ptr<_Up, _Ep>::pointer>::type _CT; |
801 | return std::less<_CT>()(__x.get(), __y.get()); |
802 | } |
803 | |
804 | /// unique_ptr comparison with nullptr |
805 | template<typename _Tp, typename _Dp> |
806 | _GLIBCXX_NODISCARD inline bool |
807 | operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) |
808 | { |
809 | return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(), |
810 | nullptr); |
811 | } |
812 | |
813 | /// unique_ptr comparison with nullptr |
814 | template<typename _Tp, typename _Dp> |
815 | _GLIBCXX_NODISCARD inline bool |
816 | operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) |
817 | { |
818 | return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr, |
819 | __x.get()); |
820 | } |
821 | |
822 | /// Relational operator for unique_ptr objects, compares the owned pointers |
823 | template<typename _Tp, typename _Dp, |
824 | typename _Up, typename _Ep> |
825 | _GLIBCXX_NODISCARD inline bool |
826 | operator<=(const unique_ptr<_Tp, _Dp>& __x, |
827 | const unique_ptr<_Up, _Ep>& __y) |
828 | { return !(__y < __x); } |
829 | |
830 | /// unique_ptr comparison with nullptr |
831 | template<typename _Tp, typename _Dp> |
832 | _GLIBCXX_NODISCARD inline bool |
833 | operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) |
834 | { return !(nullptr < __x); } |
835 | |
836 | /// unique_ptr comparison with nullptr |
837 | template<typename _Tp, typename _Dp> |
838 | _GLIBCXX_NODISCARD inline bool |
839 | operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) |
840 | { return !(__x < nullptr); } |
841 | |
842 | /// Relational operator for unique_ptr objects, compares the owned pointers |
843 | template<typename _Tp, typename _Dp, |
844 | typename _Up, typename _Ep> |
845 | _GLIBCXX_NODISCARD inline bool |
846 | operator>(const unique_ptr<_Tp, _Dp>& __x, |
847 | const unique_ptr<_Up, _Ep>& __y) |
848 | { return (__y < __x); } |
849 | |
850 | /// unique_ptr comparison with nullptr |
851 | template<typename _Tp, typename _Dp> |
852 | _GLIBCXX_NODISCARD inline bool |
853 | operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) |
854 | { |
855 | return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr, |
856 | __x.get()); |
857 | } |
858 | |
859 | /// unique_ptr comparison with nullptr |
860 | template<typename _Tp, typename _Dp> |
861 | _GLIBCXX_NODISCARD inline bool |
862 | operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) |
863 | { |
864 | return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(), |
865 | nullptr); |
866 | } |
867 | |
868 | /// Relational operator for unique_ptr objects, compares the owned pointers |
869 | template<typename _Tp, typename _Dp, |
870 | typename _Up, typename _Ep> |
871 | _GLIBCXX_NODISCARD inline bool |
872 | operator>=(const unique_ptr<_Tp, _Dp>& __x, |
873 | const unique_ptr<_Up, _Ep>& __y) |
874 | { return !(__x < __y); } |
875 | |
876 | /// unique_ptr comparison with nullptr |
877 | template<typename _Tp, typename _Dp> |
878 | _GLIBCXX_NODISCARD inline bool |
879 | operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) |
880 | { return !(__x < nullptr); } |
881 | |
882 | /// unique_ptr comparison with nullptr |
883 | template<typename _Tp, typename _Dp> |
884 | _GLIBCXX_NODISCARD inline bool |
885 | operator>=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) |
886 | { return !(nullptr < __x); } |
887 | |
888 | #ifdef __cpp_lib_three_way_comparison |
889 | template<typename _Tp, typename _Dp, typename _Up, typename _Ep> |
890 | requires three_way_comparable_with<typename unique_ptr<_Tp, _Dp>::pointer, |
891 | typename unique_ptr<_Up, _Ep>::pointer> |
892 | inline |
893 | compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer, |
894 | typename unique_ptr<_Up, _Ep>::pointer> |
895 | operator<=>(const unique_ptr<_Tp, _Dp>& __x, |
896 | const unique_ptr<_Up, _Ep>& __y) |
897 | { return compare_three_way()(__x.get(), __y.get()); } |
898 | |
899 | template<typename _Tp, typename _Dp> |
900 | requires three_way_comparable<typename unique_ptr<_Tp, _Dp>::pointer> |
901 | inline |
902 | compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer> |
903 | operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) |
904 | { |
905 | using pointer = typename unique_ptr<_Tp, _Dp>::pointer; |
906 | return compare_three_way()(__x.get(), static_cast<pointer>(nullptr)); |
907 | } |
908 | #endif |
909 | // @} relates unique_ptr |
910 | |
911 | /// @cond undocumented |
912 | template<typename _Up, typename _Ptr = typename _Up::pointer, |
913 | bool = __poison_hash<_Ptr>::__enable_hash_call> |
914 | struct __uniq_ptr_hash |
915 | #if ! _GLIBCXX_INLINE_VERSION0 |
916 | : private __poison_hash<_Ptr> |
917 | #endif |
918 | { |
919 | size_t |
920 | operator()(const _Up& __u) const |
921 | noexcept(noexcept(std::declval<hash<_Ptr>>()(std::declval<_Ptr>()))) |
922 | { return hash<_Ptr>()(__u.get()); } |
923 | }; |
924 | |
925 | template<typename _Up, typename _Ptr> |
926 | struct __uniq_ptr_hash<_Up, _Ptr, false> |
927 | : private __poison_hash<_Ptr> |
928 | { }; |
929 | /// @endcond |
930 | |
931 | /// std::hash specialization for unique_ptr. |
932 | template<typename _Tp, typename _Dp> |
933 | struct hash<unique_ptr<_Tp, _Dp>> |
934 | : public __hash_base<size_t, unique_ptr<_Tp, _Dp>>, |
935 | public __uniq_ptr_hash<unique_ptr<_Tp, _Dp>> |
936 | { }; |
937 | |
938 | #if __cplusplus201402L >= 201402L |
939 | /// @relates unique_ptr @{ |
940 | #define __cpp_lib_make_unique201304 201304 |
941 | |
942 | /// @cond undocumented |
943 | |
944 | template<typename _Tp> |
945 | struct _MakeUniq |
946 | { typedef unique_ptr<_Tp> __single_object; }; |
947 | |
948 | template<typename _Tp> |
949 | struct _MakeUniq<_Tp[]> |
950 | { typedef unique_ptr<_Tp[]> __array; }; |
951 | |
952 | template<typename _Tp, size_t _Bound> |
953 | struct _MakeUniq<_Tp[_Bound]> |
954 | { struct __invalid_type { }; }; |
955 | |
956 | /// @endcond |
957 | |
958 | /// std::make_unique for single objects |
959 | template<typename _Tp, typename... _Args> |
960 | inline typename _MakeUniq<_Tp>::__single_object |
961 | make_unique(_Args&&... __args) |
962 | { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); } |
963 | |
964 | /// std::make_unique for arrays of unknown bound |
965 | template<typename _Tp> |
966 | inline typename _MakeUniq<_Tp>::__array |
967 | make_unique(size_t __num) |
968 | { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); } |
969 | |
970 | /// Disable std::make_unique for arrays of known bound |
971 | template<typename _Tp, typename... _Args> |
972 | inline typename _MakeUniq<_Tp>::__invalid_type |
973 | make_unique(_Args&&...) = delete; |
974 | // @} relates unique_ptr |
975 | #endif // C++14 |
976 | |
977 | #if __cplusplus201402L > 201703L && __cpp_concepts |
978 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
979 | // 2948. unique_ptr does not define operator<< for stream output |
980 | /// Stream output operator for unique_ptr |
981 | template<typename _CharT, typename _Traits, typename _Tp, typename _Dp> |
982 | inline basic_ostream<_CharT, _Traits>& |
983 | operator<<(basic_ostream<_CharT, _Traits>& __os, |
984 | const unique_ptr<_Tp, _Dp>& __p) |
985 | requires requires { __os << __p.get(); } |
986 | { |
987 | __os << __p.get(); |
988 | return __os; |
989 | } |
990 | #endif // C++20 |
991 | |
992 | // @} group pointer_abstractions |
993 | |
994 | #if __cplusplus201402L >= 201703L |
995 | namespace __detail::__variant |
996 | { |
997 | template<typename> struct _Never_valueless_alt; // see <variant> |
998 | |
999 | // Provide the strong exception-safety guarantee when emplacing a |
1000 | // unique_ptr into a variant. |
1001 | template<typename _Tp, typename _Del> |
1002 | struct _Never_valueless_alt<std::unique_ptr<_Tp, _Del>> |
1003 | : std::true_type |
1004 | { }; |
1005 | } // namespace __detail::__variant |
1006 | #endif // C++17 |
1007 | |
1008 | _GLIBCXX_END_NAMESPACE_VERSION |
1009 | } // namespace |
1010 | |
1011 | #endif /* _UNIQUE_PTR_H */ |
1 | #ifndef PyObject_GetIter |
2 | struct _object; |
3 | typedef struct _object PyObject; |
4 | PyObject* clang_analyzer_PyObject_New_Reference(); |
5 | PyObject* PyObject_GetIter(PyObject *o) { |
6 | return clang_analyzer_PyObject_New_Reference(); |
7 | } |
8 | #else |
9 | #warning "API PyObject_GetIter is defined as a macro." |
10 | #endif |