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 16 #ifndef TENSORFLOW_CORE_FRAMEWORK_VARIANT_H_ 17 #define TENSORFLOW_CORE_FRAMEWORK_VARIANT_H_ 18 19 #include <functional> 20 #include <iostream> 21 #include <memory> 22 #include <type_traits> 23 #include <unordered_map> 24 #include <utility> 25 26 #include "tensorflow/core/framework/type_index.h" 27 #include "tensorflow/core/framework/variant_tensor_data.h" 28 #include "tensorflow/core/lib/core/status.h" 29 #include "tensorflow/core/lib/strings/strcat.h" 30 #include "tensorflow/core/platform/mutex.h" 31 32 namespace tensorflow { 33 34 template <typename T> 35 string TypeNameVariant(const T& value); 36 37 template <typename T> 38 string DebugStringVariant(const T& value); 39 40 // Allows for specializations of Variant Decoding. `data` may be modified in 41 // the process of decoding to `value`. 42 template <typename T> 43 bool DecodeVariant(VariantTensorData* data, T* value); 44 45 template <typename T> 46 bool DecodeVariant(string* buf, T* value); 47 48 template <typename T> 49 void EncodeVariant(const T& value, VariantTensorData* data); 50 51 template <typename T> 52 void EncodeVariant(const T& value, string* buf); 53 54 // This is an implementation of a type-erased container that can store an 55 // object of any type. The implementation is very similar to std::any, but has 56 // restrictions on the types of objects that can be stored, and eschews some of 57 // the fancier constructors available for std::any. An object of 58 // tensorflow::Variant is intended to be used as the value that will be stored 59 // in a tensorflow::Tensor object when its type is DT_VARIANT. 60 // 61 // tensorflow::Variant can store an object of a class that satisfies the 62 // following constraints: 63 // 64 // * The class is CopyConstructible. 65 // * The class has a default constructor. 66 // * It's either a protocol buffer, a tensorflow::Tensor, or defines the 67 // following functions: 68 // 69 // string TypeName() const; 70 // void Encode(VariantTensorData* data) const; 71 // void Decode(VariantTensorData data); 72 // 73 // Simple POD types can elide the Encode/Decode functions, they are provided by 74 // helper methods. 75 // Here are some typical usage patterns: 76 // 77 // Variant x = 10; 78 // EXPECT_EQ(*x.get<int>(), 10); 79 // 80 // Tensor t(DT_FLOAT, TensorShape({})); 81 // t.flat<float>()(0) = 42.0f; 82 // Variant x = t; 83 // EXPECT_EQ(x.get<Tensor>()->flat<float>()(0), 42.0f); 84 // 85 // Accessing the stored object: 86 // 87 // The get<T> function is the main mechanism to access the object 88 // stored in the container. It is type-safe, that is, calling 89 // get<T> when the stored object's type is not T, returns a 90 // nullptr. A raw pointer to the stored object can be obtained by calling 91 // get<void>(). 92 // 93 // Serializing/deserializing Variant object: 94 // 95 // The Variant class delegates serializing and deserializing operations to the 96 // contained object. Helper functions to do these operations are provided for 97 // POD data types, tensorflow::Tensor, and protocol buffer objects. However, 98 // other classes have to provide Encode/Decode functions to handle 99 // serialization. 100 // 101 // Objects stored in a Variant object often contain references to other 102 // tensorflow::Tensors of primitive types (Eg., a list of tensorflow::Tensors). 103 // To efficiently support those use cases, a structure is imposed on the 104 // serialization format. Namely, classes should serialize their contents into a 105 // VariantTensorData object: 106 // 107 // struct VariantTensorData { 108 // string type_name; 109 // string metadata; 110 // std::vector<Tensor> tensors; 111 // }; 112 // 113 // Objects with references to other Tensors can simply store those tensors in 114 // the `tensors` field, and serialize other metadata content in to the 115 // `metadata` field. 116 // 117 // Serialization example: 118 // 119 // Foo f = Foo {...}; 120 // Variant x = f; 121 // string serialized_f; 122 // x.Encode(&serialized_f); 123 // 124 // Variant y = Foo(); // default constructed Foo. 125 // y.Decode(std::move(serialized_f)); 126 // EXPECT_EQ(*x.get<Foo>(), *y.get<Foo>()); 127 // 128 // 129 // A Variant storing serialized Variant data (a value of type 130 // VariantTensorDataProto) has different behavior from a standard Variant. 131 // Namely, its TypeName matches the TypeName of the original Variant; 132 // and its non-const get method performs lazy deserialization. 133 // 134 // Decode and copy example: 135 // 136 // Foo f = Foo {...}; 137 // Variant x = f; 138 // 139 // VariantTensorData serialized_data_f; 140 // VariantTensorDataProto serialized_proto_f; 141 // x.Encode(&serialized_data_f); 142 // serialized_data_f.ToProto(&serialized_proto_f); 143 // 144 // Variant y_type_unknown = serialized_proto_f; // Store serialized Variant. 145 // 146 // EXPECT_EQ(x.TypeName(), y_type_unknown.TypeName()); // Looks like Foo. 147 // EXPECT_EQ(MakeTypeIndex<VariantTensorDataProto>(), 148 // y_type_unknown.TypeId()); 149 // 150 class Variant { 151 public: 152 constexpr Variant() noexcept = default; 153 Variant(const Variant & other)154 Variant(const Variant& other) 155 : value_(other.is_empty() ? std::unique_ptr<ValueInterface>() 156 : other.value_->Clone()) {} 157 158 Variant(Variant&& other) noexcept = default; 159 160 // Make sure that the type is CopyConstructible and not a tensorflow::Variant 161 // object itself. We want the copy constructor to be chosen for the 162 // tensorflow::Variant case. 163 template <typename T, typename VT = typename std::decay<T>::type, 164 typename std::enable_if<!std::is_same<Variant, VT>::value && 165 std::is_copy_constructible<VT>::value, 166 void>::type* = nullptr> Variant(T && value)167 Variant(T&& value) // NOLINT 168 : value_(new Value<VT>(in_place, std::forward<T>(value))) {} 169 170 Variant& operator=(const Variant& rhs) { 171 Variant(rhs).swap(*this); 172 return *this; 173 } 174 175 Variant& operator=(Variant&& rhs) noexcept { 176 Variant(std::move(rhs)).swap(*this); 177 return *this; 178 } 179 is_empty()180 bool is_empty() const { return value_ == nullptr; } 181 clear()182 void clear() noexcept { value_.reset(); } 183 swap(Variant & other)184 void swap(Variant& other) noexcept { value_.swap(other.value_); } 185 186 // Note, unlike TypeName(), TypeId() does not return the TypeIndex 187 // of the original type when a TensorValueDataProto is stored as the 188 // value. In this case, it returns the TypeIndex of TensorValueDataProto. TypeId()189 TypeIndex TypeId() const { 190 const TypeIndex VoidTypeIndex = MakeTypeIndex<void>(); 191 if (is_empty()) { 192 return VoidTypeIndex; 193 } 194 return value_->TypeId(); 195 } 196 DebugString()197 string DebugString() const { 198 return strings::StrCat("Variant<type: ", TypeName(), 199 " value: ", value_->DebugString(), ">"); 200 } 201 202 // Returns a pointer to the stored value if it is type T, or nullptr 203 // otherwise. 204 template <typename T> get()205 T* get() { 206 const TypeIndex TTypeIndex = MakeTypeIndex<T>(); 207 if (is_empty() || (TTypeIndex != TypeId())) return nullptr; 208 return std::addressof(static_cast<Variant::Value<T>*>(value_.get())->value); 209 } 210 211 // Returns a pointer to the stored value if it is type T, or nullptr 212 // otherwise. 213 template <typename T> get()214 const T* get() const { 215 const TypeIndex TTypeIndex = MakeTypeIndex<T>(); 216 if (is_empty() || (TTypeIndex != TypeId())) return nullptr; 217 return std::addressof( 218 static_cast<const Variant::Value<T>*>(value_.get())->value); 219 } 220 221 // Returns TypeNameVariant(value). 222 // 223 // In the special case that a serialized Variant is stored (value 224 // is a VariantTensorDataProto), returns value.TypeName(), the 225 // TypeName field stored in the VariantTensorDataProto buffer. TypeName()226 string TypeName() const { 227 if (is_empty()) { 228 return ""; 229 } 230 return value_->TypeName(); 231 } 232 233 // Serialize the contents of the stored object into `data`. Encode(VariantTensorData * data)234 void Encode(VariantTensorData* data) const { 235 if (!is_empty()) { 236 value_->Encode(data); 237 } 238 } 239 240 // Deserialize `data` and update the stored object. 241 bool Decode(VariantTensorData data); 242 243 // Helper methods to directly serialize/deserialize from strings. Encode(string * buf)244 void Encode(string* buf) const { 245 if (!is_empty()) { 246 value_->Encode(buf); 247 } 248 } Decode(string buf)249 bool Decode(string buf) { 250 if (!is_empty()) { 251 return value_->Decode(std::move(buf)); 252 } 253 return true; 254 } 255 256 private: 257 struct in_place_t {}; 258 static constexpr in_place_t in_place{}; 259 260 struct ValueInterface { 261 virtual ~ValueInterface() = default; 262 virtual TypeIndex TypeId() const = 0; 263 virtual void* RawPtr() = 0; 264 virtual const void* RawPtr() const = 0; 265 virtual std::unique_ptr<ValueInterface> Clone() const = 0; 266 virtual string TypeName() const = 0; 267 virtual string DebugString() const = 0; 268 virtual void Encode(VariantTensorData* data) const = 0; 269 virtual bool Decode(VariantTensorData data) = 0; 270 virtual void Encode(string* buf) const = 0; 271 virtual bool Decode(string data) = 0; 272 }; 273 274 template <typename T> 275 struct Value : ValueInterface { 276 template <class... Args> ValueValue277 explicit Value(in_place_t /*tag*/, Args&&... args) 278 : value(std::forward<Args>(args)...) {} 279 TypeIdValue280 TypeIndex TypeId() const override { 281 const TypeIndex value_type_index = 282 MakeTypeIndex<typename std::decay<T>::type>(); 283 return value_type_index; 284 } 285 RawPtrValue286 void* RawPtr() override { return &value; } 287 RawPtrValue288 const void* RawPtr() const override { return &value; } 289 CloneValue290 std::unique_ptr<ValueInterface> Clone() const override { 291 return std::unique_ptr<ValueInterface>(new Value(in_place, value)); 292 } 293 TypeNameValue294 string TypeName() const override { return TypeNameVariant(value); } 295 DebugStringValue296 string DebugString() const override { return DebugStringVariant(value); } 297 EncodeValue298 void Encode(VariantTensorData* data) const override { 299 EncodeVariant(value, data); 300 } 301 DecodeValue302 bool Decode(VariantTensorData data) override { 303 return DecodeVariant(&data, &value); 304 } 305 EncodeValue306 void Encode(string* buf) const override { EncodeVariant(value, buf); } 307 DecodeValue308 bool Decode(string buf) override { return DecodeVariant(&buf, &value); } 309 310 T value; 311 }; 312 313 // value_ can point to any type T as wrapped by a ValueInterface. 314 // The only real requirement is that T is default-constructible. 315 std::unique_ptr<ValueInterface> value_; 316 }; 317 318 template <> 319 void* Variant::get(); 320 321 template <> 322 const void* Variant::get() const; 323 324 } // end namespace tensorflow 325 326 #endif // TENSORFLOW_CORE_FRAMEWORK_VARIANT_H_ 327