Update with current status
[gnash.git] / libcore / Property.h
blob4bdb8ebd146141948a09042846b88cacaf8b87f5
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #ifndef GNASH_PROPERTY_H
21 #define GNASH_PROPERTY_H
23 #include <boost/variant.hpp>
24 #include <cassert>
25 #include <functional>
26 #include <typeinfo>
28 #include "PropFlags.h"
29 #include "as_value.h"
30 #include "ObjectURI.h"
31 #include "dsodefs.h" // for DSOTEXPORT
33 namespace gnash {
34 typedef as_value (*as_c_function_ptr)(const fn_call& fn);
35 class as_function;
38 namespace gnash {
40 /// Holder for getter/setter functions
42 /// Getter setter can be user-defined or native ones.
43 /// This class abstracts the two.
44 class GetterSetter
46 class NativeGetterSetter;
48 // The following helper structs define common operations on the
49 // Two types of GetterSetter. Some operations are applicable only to
50 // one type.
52 /// Get or set a GetterSetter
54 /// @tparam S A type that determines what operation to call on the
55 /// GetterSetter
56 /// @param Arg The type of the argument to the get or set function.
57 template<typename Arg, typename S>
58 struct GetSetVisitor : boost::static_visitor<typename S::result_type>
60 GetSetVisitor(const Arg& arg) : _arg(arg) {}
61 template<typename T> typename S::result_type operator()(T& t) const {
62 return S()(t, _arg);
64 private:
65 const Arg& _arg;
68 /// Set a GetterSetter
69 struct Set
71 typedef void result_type;
72 template<typename T, typename Arg>
73 result_type operator()(T& t, Arg& a) const {
74 t.set(a);
78 /// Get a GetterSetter
79 struct Get
81 typedef as_value result_type;
82 template<typename T, typename Arg>
83 result_type operator()(T& t, Arg& a) const {
84 return t.get(a);
88 /// Set the underlying value of a GetterSetter
90 /// This does not apply to NativeGetterSetters.
91 struct SetUnderlying : boost::static_visitor<>
93 template<typename T>
94 result_type operator()(T& gs, const as_value& val) const {
95 gs.setUnderlying(val);
97 result_type operator()(NativeGetterSetter&, const as_value&) const {}
100 /// Get the underlying value of a GetterSetter
102 /// This does not apply to NativeGetterSetters.
103 struct GetUnderlying : boost::static_visitor<as_value>
105 template<typename T>
106 result_type operator()(const T& gs) const {
107 return gs.getUnderlying();
109 result_type operator()(const NativeGetterSetter&) const {
110 return result_type();
114 /// Mark a GetterSetter reachable
115 struct MarkReachable : boost::static_visitor<>
117 template<typename T>
118 result_type operator()(const T& gs) const {
119 gs.markReachableResources();
123 public:
125 /// Construct a user-defined getter-setter
126 GetterSetter(as_function* getter, as_function* setter)
128 _getset(UserDefinedGetterSetter(getter, setter))
131 /// Construct a native getter-setter
132 GetterSetter(as_c_function_ptr getter, as_c_function_ptr setter)
134 _getset(NativeGetterSetter(getter, setter))
137 /// Invoke the getter
138 as_value get(fn_call& fn) const {
139 GetSetVisitor<const fn_call, Get> s(fn);
140 return boost::apply_visitor(s, _getset);
143 /// Invoke the setter
144 void set(const fn_call& fn) {
145 GetSetVisitor<fn_call, Set> s(fn);
146 boost::apply_visitor(s, _getset);
149 /// Set the cache value (for user-defined getter-setters)
150 void setCache(const as_value& v) {
151 boost::apply_visitor(
152 std::bind(SetUnderlying(), std::placeholders::_1, v), _getset);
155 /// Get the cache value (for user-defined getter-setters)
156 as_value getCache() const {
157 return boost::apply_visitor(GetUnderlying(), _getset);
160 void markReachableResources() const {
161 boost::apply_visitor(MarkReachable(), _getset);
164 private:
166 /// User-defined getter/setter
167 class UserDefinedGetterSetter
169 public:
171 UserDefinedGetterSetter(as_function* get, as_function* set)
173 _getter(get),
174 _setter(set),
175 _underlyingValue(),
176 _beingAccessed(false)
179 /// Invoke the getter
180 as_value get(const fn_call& fn) const;
182 /// Invoke the setter
183 void set(const fn_call& fn);
185 /// Get the underlying value
186 const as_value& getUnderlying() const { return _underlyingValue; }
188 /// Set the underlying value
189 void setUnderlying(const as_value& v) { _underlyingValue = v; }
191 void markReachableResources() const;
193 private:
195 /// For SWF6 (not higher) a user-defined getter-setter would not
196 /// be invoked while being set. This ScopedLock helps marking a
197 /// Getter-Setter as being invoked in an exception-safe manner.
199 /// Note this is not thread safe and does not attempt to provide
200 /// thread safety.
201 class ScopedLock : boost::noncopyable
203 public:
205 explicit ScopedLock(const UserDefinedGetterSetter& na)
207 _a(na),
208 _obtainedLock(_a._beingAccessed ? false : true)
210 // If we didn't obtain the lock it would be true anyway,
211 // but it's probably polite to avoid touching it.
212 if (_obtainedLock) _a._beingAccessed = true;
215 ~ScopedLock() { if ( _obtainedLock) _a._beingAccessed = false; }
217 /// Return true if the lock was obtained
219 /// If false is returned, we're being called recursively,
220 /// which means we should set the underlyingValue instead
221 /// of calling the setter (for SWF6, again).
223 bool obtainedLock() const { return _obtainedLock; }
225 private:
227 const UserDefinedGetterSetter& _a;
228 bool _obtainedLock;
232 as_function* _getter;
233 as_function* _setter;
234 as_value _underlyingValue;
235 mutable bool _beingAccessed;
238 /// Native GetterSetter
239 class NativeGetterSetter
241 public:
243 NativeGetterSetter(as_c_function_ptr get, as_c_function_ptr set)
245 _getter(get), _setter(set) {}
247 /// Invoke the getter
248 as_value get(const fn_call& fn) const {
249 return _getter(fn);
252 /// Invoke the setter
253 void set(const fn_call& fn) {
254 _setter(fn);
257 /// Nothing to do for native setters.
258 void markReachableResources() const {}
260 private:
261 as_c_function_ptr _getter;
262 as_c_function_ptr _setter;
265 boost::variant<UserDefinedGetterSetter, NativeGetterSetter> _getset;
269 /// An abstract property
271 /// A Property is a holder for a value or a getter-setter.
273 /// Properties have special const semantics: the value of a Property does
274 /// not affect its outward state, so the value of a const Property can be
275 /// changed.
276 class Property
279 /// Mark the stored value reachable.
280 struct SetReachable : boost::static_visitor<>
282 result_type operator()(const as_value& val) const {
283 val.setReachable();
285 result_type operator()(const GetterSetter& gs) const {
286 return gs.markReachableResources();
290 public:
292 Property(ObjectURI uri, const as_value& value,
293 PropFlags flags)
295 _bound(value),
296 _uri(std::move(uri)),
297 _flags(std::move(flags)),
298 _destructive(false)
301 Property(ObjectURI uri,
302 as_function* getter, as_function* setter,
303 PropFlags flags, bool destroy = false)
305 _bound(GetterSetter(getter, setter)),
306 _uri(std::move(uri)),
307 _flags(std::move(flags)),
308 _destructive(destroy)
311 Property(ObjectURI uri, as_c_function_ptr getter,
312 as_c_function_ptr setter, PropFlags flags,
313 bool destroy = false)
315 _bound(GetterSetter(getter, setter)),
316 _uri(std::move(uri)),
317 _flags(std::move(flags)),
318 _destructive(destroy)
321 /// accessor to the properties flags
322 const PropFlags& getFlags() const { return _flags; }
324 /// Set the flags of the property
325 void setFlags(const PropFlags& flags) const {
326 _flags = flags;
329 /// Get value of this property
331 /// @param this_ptr
332 /// The as_object used to set the 'this' pointer.
333 /// for calling getter function (GetterSetterProperty);
334 /// it will be unused when getting or setting SimpleProperty
335 /// properties.
336 /// @return the value of this property
338 DSOTEXPORT as_value getValue(const as_object& this_ptr) const;
340 /// Get internal cached value of this property
342 /// For simple properties, this is the usual value;
343 /// for user-defined getter-setter this is a cached value
344 /// to watch for infinitely recurse on calling the getter
345 /// or setter; Native getter-setter has no cache,
346 /// undefined will be returned for them.
347 as_value getCache() const;
349 /// Set internal cached value of this property
351 /// For simple properties, this is the usual value;
352 /// for user-defined getter-setter this is a cached value
353 /// to watch for infinitely recurse on calling the getter
354 /// or setter; Native getter-setter has no cache,
355 /// nothing would happen for them.
356 void setCache(const as_value& v);
358 /// Set value of this property
360 /// @param this_ptr The as_object used to set the 'this' pointer
361 /// for calling getter/setter function
362 /// It will be unused when getting or setting
363 /// simple properties.
364 /// This parameter is non-const as nothing prevents an
365 /// eventual "Setter" function from actually modifying it,
366 /// so we can't promise constness.
367 /// @param value The new value for this property. It will be used as first
368 /// argument of the 'setter' function if this is a Getter/Setter
369 /// property. @see isGetterSetter().
370 /// @return true if the property was set, otherwise false. Read-only
371 /// properties can generally not be set, but destructive
372 /// properties are still allowed to be replaced, as this
373 /// should be invisible to the user.
374 bool setValue(as_object& this_ptr, const as_value &value) const;
376 /// Is this a getter/setter property?
377 bool isGetterSetter() const {
378 return _bound.type() == typeid(GetterSetter);
381 /// Clear visibility flags
382 void clearVisible(int swfVersion) { _flags.clear_visible(swfVersion); }
384 /// The name-namespace pair (ObjectURI) of this Property
385 const ObjectURI& uri() const {
386 return _uri;
389 /// Mark this property as being reachable (for the GC)
390 void setReachable() const {
391 return boost::apply_visitor(SetReachable(), _bound);
394 private:
396 // Store the various types of things that can be held.
397 typedef boost::variant<as_value, GetterSetter> BoundType;
399 /// The value of the property.
400 mutable BoundType _bound;
402 /// The property identifier (name).
403 ObjectURI _uri;
405 /// Properties flags
406 mutable PropFlags _flags;
408 // If true, as soon as getValue has been invoked once, the
409 // returned value becomes a fixed return (though it can be
410 // overwritten if not readOnly)
411 mutable bool _destructive;
415 /// is this a read-only member ?
416 inline bool
417 readOnly(const Property& prop) {
418 return prop.getFlags().test<PropFlags::readOnly>();
421 /// Is this member supposed to be visible by a VM of given version ?
422 inline bool
423 visible(const Property& prop, int version) {
424 return prop.getFlags().get_visible(version);
427 } // namespace gnash
429 #endif // GNASH_PROPERTY_H