[Author: zork]
[google-gears.git] / gears / base / common / dispatcher.cc
blob78397b5088c6e77963872d1068a0cff960d494c9
1 // Copyright 2007, Google Inc.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 // 1. Redistributions of source code must retain the above copyright notice,
7 // this list of conditions and the following disclaimer.
8 // 2. Redistributions in binary form must reproduce the above copyright notice,
9 // this list of conditions and the following disclaimer in the documentation
10 // and/or other materials provided with the distribution.
11 // 3. Neither the name of Google Inc. nor the names of its contributors may be
12 // used to endorse or promote products derived from this software without
13 // specific prior written permission.
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // Don't actually include dispatcher.h, since this is a template file and will
27 // be included by the .h file. If we do, mkdepend.py explodes in a whirlwind of
28 // angry recursion as it tries to follow the infinite include chain.
30 #include "gears/base/common/js_types.h"
31 #include "gears/base/common/thread_locals.h"
33 // Returns the DispatchId associated with the given string. Used for looking
34 // up methods and properties.
35 inline DispatchId GetStringIdentifier(const char *str) {
36 #if BROWSER_NPAPI
37 return reinterpret_cast<DispatchId>(NPN_GetStringIdentifier(str));
38 #else
39 // TODO(mpcomplete): Figure out what we need for other ports.
40 // This only works if str is a static string.
41 return reinterpret_cast<DispatchId>(const_cast<char *>(str));
42 #endif
45 template<class T>
46 Dispatcher<T>::Dispatcher(ImplClass *impl) : impl_(impl) {
47 // Ensure that property and method mappings are initialized.
48 ThreadLocalVariables &locals = GetThreadLocals();
49 if (!locals.did_init_class) {
50 locals.did_init_class = true;
51 Init();
55 template<class T>
56 bool Dispatcher<T>::HasMethod(DispatchId method_id) {
57 const IDList &methods = GetMethodList();
58 return methods.find(method_id) != methods.end();
61 template<class T>
62 bool Dispatcher<T>::HasPropertyGetter(DispatchId property_id) {
63 const IDList &properties = GetPropertyGetterList();
64 return properties.find(property_id) != properties.end();
67 template<class T>
68 bool Dispatcher<T>::HasPropertySetter(DispatchId property_id) {
69 const IDList &properties = GetPropertySetterList();
70 return properties.find(property_id) != properties.end();
73 template<class T>
74 bool Dispatcher<T>::CallMethod(DispatchId method_id, JsCallContext *context) {
75 const IDList &methods = GetMethodList();
76 typename IDList::const_iterator method = methods.find(method_id);
77 if (method == methods.end())
78 return false;
79 ImplCallback callback = method->second;
81 (impl_->*callback)(context);
82 return true;
85 template<class T>
86 bool Dispatcher<T>::GetProperty(DispatchId property_id,
87 JsCallContext *context) {
88 const IDList &properties = GetPropertyGetterList();
89 typename IDList::const_iterator property = properties.find(property_id);
90 if (property == properties.end())
91 return false;
92 ImplCallback callback = property->second;
94 (impl_->*callback)(context);
95 return true;
98 template<class T>
99 bool Dispatcher<T>::SetProperty(DispatchId property_id,
100 JsCallContext *context) {
101 const IDList &properties = GetPropertySetterList();
102 typename IDList::const_iterator property = properties.find(property_id);
103 if (property == properties.end() || property->second == NULL)
104 return false;
105 ImplCallback callback = property->second;
107 (impl_->*callback)(context);
108 return true;
111 template<class T>
112 const DispatcherNameList &Dispatcher<T>::GetMemberNames() {
113 return GetThreadLocals().members;
116 template<class T>
117 DispatchId Dispatcher<T>::GetDispatchId(const std::string &member_name) {
118 DispatcherNameList member_names = GetMemberNames();
119 DispatcherNameList::iterator result = member_names.find(member_name);
120 if (result != member_names.end()) {
121 return result->second;
122 } else {
123 return NULL;
127 // static
128 template<class T>
129 void Dispatcher<T>::RegisterProperty(const char *name,
130 ImplCallback getter, ImplCallback setter) {
131 assert(getter);
132 DispatchId id = GetStringIdentifier(name);
133 GetPropertyGetterList()[id] = getter;
134 GetPropertySetterList()[id] = setter;
135 GetThreadLocals().members[name] = id;
138 // static
139 template<class T>
140 void Dispatcher<T>::RegisterMethod(const char *name, ImplCallback callback) {
141 DispatchId id = GetStringIdentifier(name);
142 GetMethodList()[id] = callback;
143 GetThreadLocals().members[name] = id;
146 // static
147 template<class T>
148 void Dispatcher<T>::DeleteThreadLocals(void *context) {
149 ThreadLocalVariables *locals =
150 reinterpret_cast<ThreadLocalVariables*>(context);
151 delete locals;
154 // static
155 template<class T>
156 typename Dispatcher<T>::ThreadLocalVariables &Dispatcher<T>::GetThreadLocals() {
157 const std::string &key = kThreadLocalsKey;
158 ThreadLocalVariables *locals =
159 reinterpret_cast<ThreadLocalVariables*>(ThreadLocals::GetValue(key));
160 if (!locals) {
161 locals = new ThreadLocalVariables;
162 ThreadLocals::SetValue(key, locals, &DeleteThreadLocals);
164 return *locals;