OLD | NEW |
| (Empty) |
1 // Copyright 2010 The Ginsu Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can | |
3 // be found in the LICENSE file. | |
4 | |
5 #ifndef C_SALT_VARIANT_H_ | |
6 #define C_SALT_VARIANT_H_ | |
7 | |
8 #include <string> | |
9 | |
10 #include "boost/static_assert.hpp" | |
11 #include "boost/type_traits/is_base_and_derived.hpp" | |
12 #include "boost/variant.hpp" | |
13 #include "c_salt/converting_visitor.h" | |
14 #include "c_salt/scriptable_native_object_ptrs.h" | |
15 #include "c_salt/scriptable_native_object.h" | |
16 #include "c_salt/scripting_interface.h" | |
17 #include "c_salt/scripting_interface_ptrs.h" | |
18 | |
19 namespace c_salt { | |
20 | |
21 class ScriptingBridge; | |
22 | |
23 // A polymorphic type container. You can always get the value as any of the | |
24 // intrisic types, no matter what the underlying storage actually is. For | |
25 // example, if you create a Variant using the string "3.14159", you can get | |
26 // its double_value(), which will be 3.14159. The value is immutable. Note: | |
27 // making copies of Variant instances using the copy constructor might cause a | |
28 // round trip to the browser in order to perform reference counting. | |
29 | |
30 class Variant { | |
31 public: | |
32 | |
33 typedef enum { | |
34 kNullVariantType, | |
35 kBoolVariantType, | |
36 kInt32VariantType, | |
37 kDoubleVariantType, | |
38 kStringVariantType, | |
39 kObjectVariantType | |
40 } VariantType; | |
41 | |
42 // Create a new Variant with the corresponding underlying storage. The caller | |
43 // is responsible for deleting the resulting Type. | |
44 Variant() : variant_type_(kNullVariantType) {} | |
45 explicit Variant(bool bool_value) | |
46 : variant_type_(kBoolVariantType), value_(bool_value) {} | |
47 explicit Variant(int32_t int32_value) | |
48 : variant_type_(kInt32VariantType), value_(int32_value) {} | |
49 explicit Variant(double double_value) | |
50 : variant_type_(kDoubleVariantType), value_(double_value) {} | |
51 // Creates a deep copy of |string_value|, this object instance manages the | |
52 // string's memory. | |
53 explicit Variant(const std::string& string_value) | |
54 : variant_type_(kStringVariantType), value_(string_value) {} | |
55 // Note that this ctor will cause two copies of |string_value| to happen. | |
56 explicit Variant(const char* string_value) | |
57 : variant_type_(kStringVariantType), value_(std::string(string_value)) {} | |
58 // Hold a shared reference to |object_value|. | |
59 explicit Variant(SharedScriptingInterface object_value) | |
60 : variant_type_(kObjectVariantType), value_(object_value) {} | |
61 | |
62 // This constructor handles creating a Variant from a pointer to | |
63 // ScriptableNativeObject. This is done by getting a shared pointer to the | |
64 // ScriptingBridge associated with the ScriptableNativeObject. | |
65 // | |
66 // If the ScriptingBridge associated with the given native object has gone | |
67 // away, then we can't represent that object in a c_salt Variant, and | |
68 // therefore the constructed Variant will be of Null type. | |
69 template <class T> | |
70 explicit Variant(boost::shared_ptr<T> native_object) | |
71 : variant_type_(kObjectVariantType) { | |
72 // This constructor only works if T inherits from ScriptableNativeObject. | |
73 BOOST_STATIC_ASSERT((boost::is_base_and_derived<ScriptableNativeObject, | |
74 T>::value)); | |
75 // Cast to the base. This is probably not necessary, but it protects us | |
76 // from users inheriting from ScriptableNativeObject but then hiding the | |
77 // GetScriptingBridge function that we want. | |
78 SharedScriptableNativeObject sno = | |
79 boost::static_pointer_cast<ScriptableNativeObject>(native_object); | |
80 WeakScriptingBridge weak_bridge = native_object->GetScriptingBridge(); | |
81 // Try to lock the weak pointer to a shared pointer. If this succeeds, then | |
82 // the scripting bridge still exists, and we can set this variant to point | |
83 // at it. | |
84 SharedScriptingInterface shared_scripting_if(weak_bridge.lock()); | |
85 if (shared_scripting_if) { | |
86 // We were able to lock the pointer, so set our internal variant to it. | |
87 value_ = shared_scripting_if; | |
88 } else { | |
89 // We failed to lock a shared_ptr, which means the ScriptingBridge for | |
90 // this object has gone away. This must be because the browser is done | |
91 // with it. Set the Variant to kNullVariantType to indicate failure. | |
92 variant_type_ = kNullVariantType; | |
93 } | |
94 } | |
95 | |
96 // TODO(dspringer,dmichael): It might be worthwhile to make a no-copy | |
97 // version of the std::string ctor variant(), but that requires a lot more | |
98 // thought. For reference, see, e.g. CFStringCreateWithCharactersNoCopy() | |
99 // here: | |
100 // http://developer.apple.com/library/mac/#documentation/CoreFoundation | |
101 // /Reference/CFStringRef/Reference/reference.html | |
102 // static Variant* CreateWithStringNoCopy(const std::string* string_value); | |
103 | |
104 // The dtor potentially does a round-trip to the browser in the event that | |
105 // the underlying storage type is ref counted. | |
106 virtual ~Variant(); | |
107 | |
108 VariantType variant_type() const { | |
109 return variant_type_; | |
110 } | |
111 | |
112 // Always succeeds. Conversion rules: | |
113 // Convert from higher precision to lower (e.g. double to int): the | |
114 // higher precision value is truncated towards 0. | |
115 // Convert number to string: the formatted equivalent of printf() with %d or | |
116 // %g is used. | |
117 // Convert bool to number: true -> 1, false -> 0. | |
118 // Convert number to bool: non-0 -> true, 0 within epsilon -> false. | |
119 // Convert bool to string: true -> "true", false -> "false". | |
120 // Convert string to bool: if the string starts with 't', 'y' or '1' (case | |
121 // insensitive) -> true; if it starts with anything else -> false. | |
122 // Convert string to number: any format recognized by strol() or strtod() | |
123 // (see the POSIX man mages for these functions for more details) is | |
124 // converted to a corresponding numeric value; strings that cannot be | |
125 // converted this way produce a 0 (the double value is exactly 0.0). | |
126 template <class T> | |
127 T GetValue() const { | |
128 ConvertingVisitor<T> visitor; | |
129 return boost::apply_visitor(visitor, value_); | |
130 } | |
131 | |
132 // Convenience wrappers. | |
133 bool BoolValue() const { | |
134 return GetValue<bool>(); | |
135 } | |
136 int32_t Int32Value() const { | |
137 return GetValue<int32_t>(); | |
138 } | |
139 double DoubleValue() const { | |
140 return GetValue<double>(); | |
141 } | |
142 std::string StringValue() const { | |
143 return GetValue<std::string>(); | |
144 } | |
145 SharedScriptingInterface ObjectValue() const { | |
146 return GetValue<SharedScriptingInterface>(); | |
147 } | |
148 | |
149 // TODO(dspringer, dmichael): Add other more specific accessors that give | |
150 // more information about possible conversions and conversion errors. | |
151 /* | |
152 template <class T> | |
153 T GetValue(bool* did_convert) const; | |
154 */ | |
155 | |
156 friend bool operator==(const Variant&, const Variant&); | |
157 | |
158 private: | |
159 VariantType variant_type_; | |
160 boost::variant<bool, | |
161 int32_t, | |
162 double, | |
163 std::string, | |
164 SharedScriptingInterface> value_; | |
165 // Variants are immutable. You can copy them, but assignment is not | |
166 // allowed. | |
167 Variant& operator=(const Variant&); // Not implemented, do not use. | |
168 }; | |
169 | |
170 } // namespace c_salt | |
171 | |
172 #endif // C_SALT_VARIANT_H_ | |
OLD | NEW |