GraphLab: Distributed Graph-Parallel API  2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
any.hpp
1 /**
2  * Copyright (c) 2009 Carnegie Mellon University.
3  * All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing,
12  * software distributed under the License is distributed on an "AS
13  * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14  * express or implied. See the License for the specific language
15  * governing permissions and limitations under the License.
16  *
17  * For more about this software visit:
18  *
19  * http://www.graphlab.ml.cmu.edu
20  *
21  */
22 
23 
24 // Modified from boost 1.37 boost::any
25 // Extended to handle graphlab graphlab/serialization/deserialization functions
26 // See http://www.boost.org/libs/any for Documentation.
27 
28 #ifndef GRAPHLAB_ANY_INCLUDED
29 #define GRAPHLAB_ANY_INCLUDED
30 
31 // what: variant type boost::any
32 // who: contributed by Kevlin Henney,
33 // with features contributed and bugs found by
34 // Ed Brey, Mark Rodgers, Peter Dimov, and James Curran
35 // when: July 2001
36 // where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95
37 
38 #include <algorithm>
39 #include <typeinfo>
40 #include <map>
41 #include <iostream>
42 #include <stdint.h>
43 
44 #include <boost/type_traits/remove_reference.hpp>
45 #include <boost/type_traits/is_reference.hpp>
46 #include <boost/throw_exception.hpp>
47 #include <boost/static_assert.hpp>
48 #include <boost/utility.hpp>
49 #include <boost/exception/detail/is_output_streamable.hpp>
50 #include <boost/functional/hash.hpp>
51 
52 
53 #include <graphlab/logger/assertions.hpp>
54 #include <graphlab/serialization/serialization_includes.hpp>
55 
56 namespace graphlab {
57  /**
58  A generic "variant" object obtained from Boost::Any and modified to
59  be serializable. A variable of type "any" can store any datatype
60  (even dynamically changeable at runtime), but the caveat is that
61  you must know the exact stored type to be able to extract the data
62  safely.
63 
64  To serialize/deserialize the any, regular serialization procedures
65  apply. However, since a statically initialized type registration
66  system is used to identify the type of the deserialized object, so
67  the user must pay attention to a couple of minor issues.
68 
69  On serialization:
70 
71  \li \b a) If an any contains a serializable type, the any can be
72  serialized.
73  \li \b b) If an any contains an unserializable type, the
74  serialization will fail at runtime.
75 
76  On deserialization:
77 
78  \li \b c) An empty any can be constructed with no type information
79  and it can be deserialized from an archive.
80  \li \b d) However, the deserialization will fail at runtime if the
81  true type of the any is never accessed / instantiated
82  anywhere in the code.
83 
84  Condition \b d) is particular unusual so I will illustrate with an
85  example.
86 
87  Given a simple user struct:
88  \code
89  struct UserStruct {
90  int i;
91  void save (graphlab::oarchive& oarc) const {
92  oarc << i;
93  }
94  void load (graphlab::iarchive& iarc) {
95  iarc << i;
96  }
97  }
98  \endcode
99 
100  If an any object contains the struct, it will be serializable.
101 
102  \code
103  UserStruct us;
104  us.i = 10;
105  any a = us;
106  // output file
107  std::ofstream fout("test.bin");
108  graphlab::oarchive oarc(fout);
109  oarc << a; // write the any
110  \endcode
111 
112  To deserialize, I will open an input archive and stream into an any.
113 
114  \code
115  // open input
116  std::ifstream fin("test.bin");
117  graphlab::iarchive iarc(fin);
118  // create an any and read it
119  any a;
120  iarc >> a;
121  \endcode
122 
123  Now, unusually, the above code will fail, while the following code
124  will succeed
125 
126  \code
127  // open input
128  std::ifstream fin("test.bin");
129  graphlab::iarchive iarc(fin);
130  // create an any and read it
131  any a;
132  iarc >> a;
133  std::cout << a.as<UserStruct>().i;
134  \endcode
135 
136  The <tt> a.as<UserStruct>() </tt> forces the instantiation of static functions
137  which allow the any deserialization to identify the UserStruct type.
138  */
139  class any {
140  private:
141  /**
142  * iholder is the base abstract type used to store the contents
143  */
144  class iholder {
145  public: // structors
146  virtual ~iholder() { }
147  virtual const std::type_info& type() const = 0;
148  virtual iholder * clone() const = 0;
149  virtual uint64_t deserializer_id() const = 0;
150  virtual void deep_op_equal(const iholder* c) = 0;
151  static iholder* load(iarchive_soft_fail &arc);
152  virtual void save(oarchive_soft_fail& arc) const = 0;
153  virtual std::ostream& print(std::ostream& out) const = 0;
154  };
155  iholder* contents;
156 
157  public: // structors
158  /// default constructor. Creates an empty any
159  any() : contents(NULL) { }
160 
161  /// Creates an any which stores the value
162  template<typename ValueType>
163  explicit any(const ValueType& value)
164  : contents(new holder<ValueType>(value)) { }
165 
166  /// Construct an any from another any
167  any(const any & other) :
168  contents(other.empty() ? NULL : other.contents->clone()) { }
169 
170  /// Destroy the contentss of this any
171  ~any() { delete contents; }
172 
173  /// Returns true if the object does not contain any stored data
174  bool empty() const { return contents == NULL; }
175 
176  /// Extracts a reference to the contents of the any as a type of
177  /// ValueType
178  template<typename ValueType>
179  ValueType& as() {
180  DASSERT_TRUE(type() == typeid(ValueType));
181  DASSERT_FALSE(empty());
182  return static_cast<holder<ValueType> *>(contents)->contents;
183  }
184 
185  /// Extracts a constant reference to the contents of the any as a
186  /// type of ValueType
187  template<typename ValueType>
188  inline const ValueType& as() const{
189  DASSERT_TRUE(type() == typeid(ValueType));
190  DASSERT_FALSE(empty());
191  return static_cast< holder<ValueType> *>(contents)->contents;
192  }
193 
194  /// Exchanges the contents of two any's
195  any& swap(any & rhs) {
196  std::swap(contents, rhs.contents);
197  return *this;
198  }
199 
200  /**
201  * Update the contents of this any. If a new type is used than
202  * the type of this any will change.
203  */
204  template<typename ValueType>
205  any& operator=(const ValueType & rhs) {
206  if (contents != NULL && contents->type() == typeid(ValueType)) {
207  as<ValueType>() = rhs;
208  } else { any(rhs).swap(*this); }
209  return *this;
210  }
211 
212  /**
213  * Update the contents of this any to match the type of the other
214  * any.
215  */
216  any& operator=(const any & rhs) {
217  if (rhs.empty()) {
218  if (contents) delete contents;
219  contents = NULL;
220  } else {
221  if (contents != NULL && contents->type() == rhs.contents->type()) {
222  contents->deep_op_equal(rhs.contents);
223  } else { any(rhs).swap(*this); }
224  }
225  return *this;
226  }
227 
228  std::ostream& print(std::ostream& out) const {
229  return empty()? (out << "EMPTY") : contents->print(out);
230  }
231 
232  /// Returns the type information of the stored data.
233  const std::type_info& type() const {
234  return empty() ? typeid(void) : contents->type();
235  }
236 
237  /// Return the name of the internal type as a string.
238  const std::string type_name() const {
239  return empty() ? "NULL" : std::string(contents->type().name());
240  }
241 
242  /// loads the any from a file.
243  void load(iarchive& arc) {
244  iarchive_soft_fail isoftarc(arc);
245  if(contents != NULL) { delete contents; contents = NULL; }
246  bool isempty(true);
247  isoftarc >> isempty;
248  if (isempty == false) contents = iholder::load(isoftarc);
249  }
250 
251  /// Saves the any to a file. Caveats apply. See the main any docs.
252  void save(oarchive& arc) const {
253  oarchive_soft_fail osoftarc(arc);
254  bool isempty = empty();
255  osoftarc << isempty;
256  if (isempty == false) contents->save(osoftarc);
257  }
258 
259 
260  public:
261  /**
262  * This section contain the global registry used to determine the
263  * deserialization code for a particular type. Essentially the
264  * registry is a global map in which all subtypes of iholder
265  * register a deserialization function with their type.
266  */
267 
268  typedef iholder* (*deserialize_function_type)(iarchive_soft_fail& arc);
269  typedef std::map<uint64_t, deserialize_function_type> registry_map_type;
270  /**
271  * The get registry routine is a static method that gets a
272  * reference to the global registry. It is very important that
273  * this be a static method and not a static member to ensure that
274  * the global registry is defined before each holders try to
275  * register. This is accomplished by having get_registry
276  * statically declare the global registry
277  */
278  static registry_map_type& get_global_registry();
279 
280  public:
281 
282  template <typename ValueType> static
283  typename boost::disable_if_c<boost::is_output_streamable<ValueType>::value,
284  void>::type
285  print_type_or_contents(std::ostream& out, const ValueType &h) {
286  out << "Not_Printable[" << typeid(ValueType).name() << ']';
287  }
288 
289  template <typename ValueType> static
290  typename boost::enable_if_c<boost::is_output_streamable<ValueType>::value,
291  void>::type
292  print_type_or_contents(std::ostream& out, const ValueType &h) { out << h; }
293 
294 
295  public:
296 
297  /**
298  * holder is an instantiation of iholder
299  */
300  template<typename ValueType>
301  class holder : public iholder {
302  public:
303  typedef ValueType value_type;
304  /// The actual contents of the holder
305  ValueType contents;
306  /// Construct a holder from a value
307  holder(const ValueType& value) : contents(value) { }
308  /// Construct a holder from an archive
310  /// Get the type info of the holder
311  const std::type_info& type() const { return typeid(ValueType); }
312  /// Clone a holder
313  iholder* clone() const { return new holder(contents); }
314  /// Deep assignment
315  void deep_op_equal(const iholder* other) {
316  contents = static_cast< const holder<ValueType>* >(other)->contents;
317  }
318  /**
319  * Get the deserializer id from the static registry associated
320  * with this type of holder
321  */
322  uint64_t deserializer_id() const { return registry.localid; }
323  void save(oarchive_soft_fail &arc) const {
324  arc << registry.localid << contents;
325  }
326  /**
327  * Print the contents or the type if the contents does not
328  * support printing
329  */
330  std::ostream& print(std::ostream& out) const {
331  any::print_type_or_contents(out, contents);
332  return out;
333  }
334  /** The actual deserialization function for this holder type */
335  static iholder* deserialize(iarchive_soft_fail &arc) {
336  return new holder(arc);
337  }
338  /**
339  * The following struct defines the static member used to
340  * automatically register the deserialization function for this
341  * holder type and cache a shared id used to quickly identify
342  * the deserialization function.
343  *
344  * Note that the registry actually uses the NAME of the type so
345  * renaming a type will result in an incompatible
346  * deserialization.
347  */
348  struct registry_type {
349  uint64_t localid;
350  registry_type() {
351  boost::hash<std::string> hash_function;
352  // compute localid
353  localid = hash_function(typeid(ValueType).name());
355  }
356  }; // end of registry type
357  /**
358  * The registry is a static member that will get constructed
359  * before main and used to register the any type
360  */
362  private:
363  holder& operator=(const holder& other) { }
364  }; // end of class holder
365 
366  }; // end of class any
367 
368 
369  /**
370  * This static membery computes the holder (type specific)
371  * deserialization id and also registers it with the global
372  * registry.
373  */
374  template<typename ValueType>
375  typename any::holder<ValueType>::registry_type any::holder<ValueType>::registry;
376 
377 } // namespace graphlab
378 
379 std::ostream& operator<<(std::ostream& out, const graphlab::any& any);
380 
381 
382 // Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
383 //
384 // Distributed under the Boost Software License, Version 1.0. (See
385 // accompanying file LICENSE_1_0.txt or copy at
386 // http://www.boost.org/LICENSE_1_0.txt)
387 
388 #endif
389