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