| File: | .cache/bazel/_bazel_alan/39be661231df2a680c9b74265384c13c/execroot/org_tensorflow/tensorflow/python/util/util.cc | 
| Warning: | line 536, column 16 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_GetAttrString | 
| 2 | struct _object; | 
| 3 | typedef struct _object PyObject; | 
| 4 | PyObject* clang_analyzer_PyObject_New_Reference(); | 
| 5 | PyObject* PyObject_GetAttrString(PyObject *o, const char *attr_name) { | 
| 6 | return clang_analyzer_PyObject_New_Reference(); | 
| 7 | } | 
| 8 | #else | 
| 9 | #warning "API PyObject_GetAttrString is defined as a macro." | 
| 10 | #endif |