update copyright date
[gnash.git] / libcore / Property.h
blob6e07335fa546d281518e1ff9f75dfa64f361f22d
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
3 // 2011 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 <boost/bind.hpp>
26 #include <typeinfo>
28 #include "PropFlags.h"
29 #include "as_value.h"
30 #include "ObjectURI.h"
32 namespace gnash {
33 typedef as_value (*as_c_function_ptr)(const fn_call& fn);
34 class as_function;
37 namespace gnash {
39 /// Holder for getter/setter functions
41 /// Getter setter can be user-defined or native ones.
42 /// This class abstracts the two.
43 class GetterSetter
45 class NativeGetterSetter;
47 // The following helper structs define common operations on the
48 // Two types of GetterSetter. Some operations are applicable only to
49 // one type.
51 /// Get or set a GetterSetter
53 /// @tparam S A type that determines what operation to call on the
54 /// GetterSetter
55 /// @param Arg The type of the argument to the get or set function.
56 template<typename Arg, typename S>
57 struct GetSetVisitor : boost::static_visitor<typename S::result_type>
59 GetSetVisitor(const Arg& arg) : _arg(arg) {}
60 template<typename T> typename S::result_type operator()(T& t) const {
61 return S()(t, _arg);
63 private:
64 const Arg& _arg;
67 /// Set a GetterSetter
68 struct Set
70 typedef void result_type;
71 template<typename T, typename Arg>
72 result_type operator()(T& t, Arg& a) const {
73 t.set(a);
77 /// Get a GetterSetter
78 struct Get
80 typedef as_value result_type;
81 template<typename T, typename Arg>
82 result_type operator()(T& t, Arg& a) const {
83 return t.get(a);
87 /// Set the underlying value of a GetterSetter
89 /// This does not apply to NativeGetterSetters.
90 struct SetUnderlying : boost::static_visitor<>
92 template<typename T>
93 result_type operator()(T& gs, const as_value& val) const {
94 gs.setUnderlying(val);
96 result_type operator()(NativeGetterSetter&, const as_value&) const {}
99 /// Get the underlying value of a GetterSetter
101 /// This does not apply to NativeGetterSetters.
102 struct GetUnderlying : boost::static_visitor<as_value>
104 template<typename T>
105 result_type operator()(const T& gs) const {
106 return gs.getUnderlying();
108 result_type operator()(const NativeGetterSetter&) const {
109 return result_type();
113 /// Mark a GetterSetter reachable
114 struct MarkReachable : boost::static_visitor<>
116 template<typename T>
117 result_type operator()(const T& gs) const {
118 gs.markReachableResources();
122 public:
124 /// Construct a user-defined getter-setter
125 GetterSetter(as_function* getter, as_function* setter)
127 _getset(UserDefinedGetterSetter(getter, setter))
130 /// Construct a native getter-setter
131 GetterSetter(as_c_function_ptr getter, as_c_function_ptr setter)
133 _getset(NativeGetterSetter(getter, setter))
136 /// Invoke the getter
137 as_value get(fn_call& fn) const {
138 GetSetVisitor<const fn_call, Get> s(fn);
139 return boost::apply_visitor(s, _getset);
142 /// Invoke the setter
143 void set(const fn_call& fn) {
144 GetSetVisitor<fn_call, Set> s(fn);
145 boost::apply_visitor(s, _getset);
148 /// Set the cache value (for user-defined getter-setters)
149 void setCache(const as_value& v) {
150 boost::apply_visitor(boost::bind(SetUnderlying(), _1, v), _getset);
153 /// Get the cache value (for user-defined getter-setters)
154 as_value getCache() const {
155 return boost::apply_visitor(GetUnderlying(), _getset);
158 void markReachableResources() const {
159 boost::apply_visitor(MarkReachable(), _getset);
162 private:
164 /// User-defined getter/setter
165 class UserDefinedGetterSetter
167 public:
169 UserDefinedGetterSetter(as_function* get, as_function* set)
171 _getter(get),
172 _setter(set),
173 _underlyingValue(),
174 _beingAccessed(false)
177 /// Invoke the getter
178 as_value get(const fn_call& fn) const;
180 /// Invoke the setter
181 void set(const fn_call& fn);
183 /// Get the underlying value
184 const as_value& getUnderlying() const { return _underlyingValue; }
186 /// Set the underlying value
187 void setUnderlying(const as_value& v) { _underlyingValue = v; }
189 void markReachableResources() const;
191 private:
193 /// For SWF6 (not higher) a user-defined getter-setter would not
194 /// be invoked while being set. This ScopedLock helps marking a
195 /// Getter-Setter as being invoked in an exception-safe manner.
197 /// Note this is not thread safe and does not attempt to provide
198 /// thread safety.
199 class ScopedLock : boost::noncopyable
201 public:
203 explicit ScopedLock(const UserDefinedGetterSetter& na)
205 _a(na),
206 _obtainedLock(_a._beingAccessed ? false : true)
208 // If we didn't obtain the lock it would be true anyway,
209 // but it's probably polite to avoid touching it.
210 if (_obtainedLock) _a._beingAccessed = true;
213 ~ScopedLock() { if ( _obtainedLock) _a._beingAccessed = false; }
215 /// Return true if the lock was obtained
217 /// If false is returned, we're being called recursively,
218 /// which means we should set the underlyingValue instead
219 /// of calling the setter (for SWF6, again).
221 bool obtainedLock() const { return _obtainedLock; }
223 private:
225 const UserDefinedGetterSetter& _a;
226 bool _obtainedLock;
230 as_function* _getter;
231 as_function* _setter;
232 as_value _underlyingValue;
233 mutable bool _beingAccessed;
236 /// Native GetterSetter
237 class NativeGetterSetter
239 public:
241 NativeGetterSetter(as_c_function_ptr get, as_c_function_ptr set)
243 _getter(get), _setter(set) {}
245 /// Invoke the getter
246 as_value get(const fn_call& fn) const {
247 return _getter(fn);
250 /// Invoke the setter
251 void set(const fn_call& fn) {
252 _setter(fn);
255 /// Nothing to do for native setters.
256 void markReachableResources() const {}
258 private:
259 as_c_function_ptr _getter;
260 as_c_function_ptr _setter;
263 boost::variant<UserDefinedGetterSetter, NativeGetterSetter> _getset;
267 /// An abstract property
269 /// A Property is a holder for a value or a getter-setter.
271 /// Properties have special const semantics: the value of a Property does
272 /// not affect its outward state, so the value of a const Property can be
273 /// changed.
274 class Property
277 /// Mark the stored value reachable.
278 struct SetReachable : boost::static_visitor<>
280 result_type operator()(const as_value& val) const {
281 val.setReachable();
283 result_type operator()(const GetterSetter& gs) const {
284 return gs.markReachableResources();
288 public:
290 Property(const ObjectURI& uri, const as_value& value,
291 const PropFlags& flags)
293 _bound(value),
294 _uri(uri),
295 _flags(flags),
296 _destructive(false)
299 Property(const ObjectURI& uri,
300 as_function* getter, as_function* setter,
301 const PropFlags& flags, bool destroy = false)
303 _bound(GetterSetter(getter, setter)),
304 _uri(uri),
305 _flags(flags),
306 _destructive(destroy)
309 Property(const ObjectURI& uri, as_c_function_ptr getter,
310 as_c_function_ptr setter, const PropFlags& flags,
311 bool destroy = false)
313 _bound(GetterSetter(getter, setter)),
314 _uri(uri),
315 _flags(flags),
316 _destructive(destroy)
319 /// Copy constructor
320 Property(const Property& p)
322 _bound(p._bound),
323 _uri(p._uri),
324 _flags(p._flags),
325 _destructive(p._destructive)
328 /// accessor to the properties flags
329 const PropFlags& getFlags() const { return _flags; }
331 /// Set the flags of the property
332 void setFlags(const PropFlags& flags) const {
333 _flags = flags;
336 /// Get value of this property
338 /// @param this_ptr
339 /// The as_object used to set the 'this' pointer.
340 /// for calling getter function (GetterSetterProperty);
341 /// it will be unused when getting or setting SimpleProperty
342 /// properties.
343 /// @return the value of this property
345 as_value getValue(const as_object& this_ptr) const;
347 /// Get internal cached value of this property
349 /// For simple properties, this is the usual value;
350 /// for user-defined getter-setter this is a cached value
351 /// to watch for infinitely recurse on calling the getter
352 /// or setter; Native getter-setter has no cache,
353 /// undefined will be returned for them.
354 as_value getCache() const;
356 /// Set internal cached value of this property
358 /// For simple properties, this is the usual value;
359 /// for user-defined getter-setter this is a cached value
360 /// to watch for infinitely recurse on calling the getter
361 /// or setter; Native getter-setter has no cache,
362 /// nothing would happen for them.
363 void setCache(const as_value& v);
365 /// Set value of this property
367 /// @param this_ptr
368 /// The as_object used to set the 'this' pointer.
369 /// for calling getter/setter function (GetterSetterProperty);
370 /// it will be unused when getting or setting SimpleProperty
371 /// properties.
372 /// This parameter is non-const as nothing prevents an
373 /// eventual "Setter" function from actually modifying it,
374 /// so we can't promise constness.
376 /// @param value
377 /// The new value for this property. It will be used as first
378 /// argument of the 'setter' function if this is a Getter/Setter
379 /// property. @see isGetterSetter().
380 void setValue(as_object& this_ptr, const as_value &value) const;
382 /// Is this a getter/setter property?
383 bool isGetterSetter() const {
384 return _bound.type() == typeid(GetterSetter);
387 /// Clear visibility flags
388 void clearVisible(int swfVersion) { _flags.clear_visible(swfVersion); }
390 /// The name-namespace pair (ObjectURI) of this Property
391 const ObjectURI& uri() const {
392 return _uri;
395 /// Mark this property as being reachable (for the GC)
396 void setReachable() const {
397 return boost::apply_visitor(SetReachable(), _bound);
400 private:
402 // Store the various types of things that can be held.
403 typedef boost::variant<as_value, GetterSetter> BoundType;
405 /// The value of the property.
406 mutable BoundType _bound;
408 /// The property identifier (name).
409 ObjectURI _uri;
411 /// Properties flags
412 mutable PropFlags _flags;
414 // If true, as soon as getValue has been invoked once, the
415 // returned value becomes a fixed return (though it can be
416 // overwritten if not readOnly)
417 mutable bool _destructive;
421 /// is this a read-only member ?
422 inline bool
423 readOnly(const Property& prop) {
424 return prop.getFlags().test<PropFlags::readOnly>();
427 /// Is this member supposed to be visible by a VM of given version ?
428 inline bool
429 visible(const Property& prop, int version) {
430 return prop.getFlags().get_visible(version);
433 } // namespace gnash
435 #endif // GNASH_PROPERTY_H