14800022867bf9f9535bfc1472fb5b814ad7b961
[WebKit-https.git] / JavaScriptCore / kjs / lookup.h
1 // -*- c-basic-offset: 2 -*-
2 /*
3  *  This file is part of the KDE libraries
4  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
5  *  Copyright (C) 2003 Apple Computer, Inc.
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #ifndef _KJSLOOKUP_H_
24 #define _KJSLOOKUP_H_
25
26 #include "identifier.h"
27 #include "object.h"
28 #include <stdio.h>
29
30 namespace KJS {
31
32   /**
33    * An entry in a hash table.
34    */
35   struct HashEntry {
36     /**
37      * s is the key (e.g. a property name)
38      */
39     const char *s;
40     /**
41      * value is the result value (usually an enum value)
42      */
43     int value;
44     /**
45      * attr is a set for flags (e.g. the property flags, see object.h)
46      */
47     short int attr;
48     /**
49      * params is another number. For property hashtables, it is used to
50      * denote the number of argument of the function
51      */
52     short int params;
53     /**
54      * next is the pointer to the next entry for the same hash value
55      */
56     const HashEntry *next;
57   };
58
59   /**
60    * A hash table
61    * Usually the hashtable is generated by the create_hash_table script, from a .table file.
62    *
63    * The implementation uses an array of entries, "size" is the total size of that array.
64    * The entries between 0 and hashSize-1 are the entry points
65    * for each hash value, and the entries between hashSize and size-1
66    * are the overflow entries for the hash values that need one.
67    * The "next" pointer of the entry links entry points to overflow entries,
68    * and links overflow entries between them.
69    */
70   struct HashTable {
71     /**
72      * type is a version number. Currently always 2
73      */
74     int type;
75     /**
76      * size is the total number of entries in the hashtable, including the null entries,
77      * i.e. the size of the "entries" array.
78      * Used to iterate over all entries in the table
79      */
80     int size;
81     /**
82      * pointer to the array of entries
83      * Mind that some entries in the array are null (0,0,0,0).
84      */
85     const HashEntry *entries;
86     /**
87      * the maximum value for the hash. Always smaller than size.
88      */
89     int hashSize;
90   };
91
92   /**
93    * @short Fast keyword lookup.
94    */
95   class Lookup {
96   public:
97     /**
98      * Find an entry in the table, and return its value (i.e. the value field of HashEntry)
99      */
100     static int find(const struct HashTable *table, const Identifier &s);
101     static int find(const struct HashTable *table,
102                     const UChar *c, unsigned int len);
103
104     /**
105      * Find an entry in the table, and return the entry
106      * This variant gives access to the other attributes of the entry,
107      * especially the attr field.
108      */
109     static const HashEntry* findEntry(const struct HashTable *table,
110                                       const Identifier &s);
111     static const HashEntry* findEntry(const struct HashTable *table,
112                                       const UChar *c, unsigned int len);
113
114     /**
115      * Calculate the hash value for a given key
116      */
117     static unsigned int hash(const Identifier &key);
118     static unsigned int hash(const UChar *c, unsigned int len);
119     static unsigned int hash(const char *s);
120   };
121
122   class ExecState;
123   class UString;
124   /**
125    * @internal
126    * Helper for lookupFunction and lookupValueOrFunction
127    */
128   template <class FuncImp>
129   inline Value lookupOrCreateFunction(ExecState *exec, const Identifier &propertyName,
130                                       const ObjectImp *thisObj, int token, int params, int attr)
131   {
132       // Look for cached value in dynamic map of properties (in ObjectImp)
133       ValueImp * cachedVal = thisObj->ObjectImp::getDirect(propertyName);
134       /*if (cachedVal)
135         fprintf(stderr, "lookupOrCreateFunction: Function -> looked up in ObjectImp, found type=%d\n", cachedVal->type());*/
136       if (cachedVal)
137         return Value(cachedVal);
138
139       Value val = Value(new FuncImp(exec,token, params));
140       ObjectImp *thatObj = const_cast<ObjectImp *>(thisObj);
141       thatObj->ObjectImp::put(exec, propertyName, val, attr);
142       return val;
143   }
144
145   /**
146    * Helper method for property lookups
147    *
148    * This method does it all (looking in the hashtable, checking for function
149    * overrides, creating the function or retrieving from cache, calling
150    * getValueProperty in case of a non-function property, forwarding to parent if
151    * unknown property).
152    *
153    * Template arguments:
154    * @param FuncImp the class which implements this object's functions
155    * @param ThisImp the class of "this". It must implement the getValueProperty(exec,token) method,
156    * for non-function properties.
157    * @param ParentImp the class of the parent, to propagate the lookup.
158    *
159    * Method arguments:
160    * @param exec execution state, as usual
161    * @param propertyName the property we're looking for
162    * @param table the static hashtable for this class
163    * @param thisObj "this"
164    */
165   template <class FuncImp, class ThisImp, class ParentImp>
166   inline Value lookupGet(ExecState *exec, const Identifier &propertyName,
167                          const HashTable* table, const ThisImp* thisObj)
168   {
169     const HashEntry* entry = Lookup::findEntry(table, propertyName);
170
171     if (!entry) // not found, forward to parent
172       return thisObj->ParentImp::get(exec, propertyName);
173
174     //fprintf(stderr, "lookupGet: found value=%d attr=%d\n", entry->value, entry->attr);
175     if (entry->attr & Function)
176       return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr);
177     return thisObj->getValueProperty(exec, entry->value);
178   }
179
180   /**
181    * Simplified version of lookupGet in case there are only functions.
182    * Using this instead of lookupGet prevents 'this' from implementing a dummy getValueProperty.
183    */
184   template <class FuncImp, class ParentImp>
185   inline Value lookupGetFunction(ExecState *exec, const Identifier &propertyName,
186                          const HashTable* table, const ObjectImp* thisObj)
187   {
188     const HashEntry* entry = Lookup::findEntry(table, propertyName);
189
190     if (!entry) // not found, forward to parent
191       return static_cast<const ParentImp *>(thisObj)->ParentImp::get(exec, propertyName);
192
193     if (entry->attr & Function)
194       return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr);
195
196     fprintf(stderr, "Function bit not set! Shouldn't happen in lookupGetFunction!\n" );
197     return Undefined();
198   }
199
200   /**
201    * Simplified version of lookupGet in case there are no functions, only "values".
202    * Using this instead of lookupGet removes the need for a FuncImp class.
203    */
204   template <class ThisImp, class ParentImp>
205   inline Value lookupGetValue(ExecState *exec, const Identifier &propertyName,
206                            const HashTable* table, const ThisImp* thisObj)
207   {
208     const HashEntry* entry = Lookup::findEntry(table, propertyName);
209
210     if (!entry) // not found, forward to parent
211       return thisObj->ParentImp::get(exec, propertyName);
212
213     if (entry->attr & Function)
214       fprintf(stderr, "Function bit set! Shouldn't happen in lookupGetValue! propertyName was %s\n", propertyName.ascii() );
215     return thisObj->getValueProperty(exec, entry->value);
216   }
217
218   /**
219    * This one is for "put".
220    * Lookup hash entry for property to be set, and set the value.
221    */
222   template <class ThisImp, class ParentImp>
223   inline void lookupPut(ExecState *exec, const Identifier &propertyName,
224                         const Value& value, int attr,
225                         const HashTable* table, const ThisImp* thisObj)
226   {
227     const HashEntry* entry = Lookup::findEntry(table, propertyName);
228
229     if (!entry) // not found: forward to parent
230       thisObj->ParentImp::put(exec, propertyName, value, attr);
231     else if (entry->attr & Function) // function: put as override property
232       thisObj->ObjectImp::put(exec, propertyName, value, attr);
233     else if (entry->attr & ReadOnly) // readonly! Can't put!
234 #ifdef KJS_VERBOSE
235       fprintf(stderr,"WARNING: Attempt to change value of readonly property '%s'\n",propertyName.ascii());
236 #else
237       ; // do nothing
238 #endif
239     else
240       thisObj->putValueProperty(exec, entry->value, value, attr);
241   }
242
243   /*
244    * List of things to do when porting an objectimp to the 'static hashtable' mechanism:
245    * - write the hashtable source, between @begin and @end
246    * - add a rule to build the .lut.h
247    * - include the .lut.h
248    * - mention the table in the classinfo (add a classinfo if necessary)
249    * - write/update the class enum (for the tokens)
250    * - turn get() into getValueProperty(), put() into putValueProperty(), using a switch and removing funcs
251    * - write get() and/or put() using a template method
252    * - cleanup old stuff (e.g. hasProperty)
253    * - compile, test, commit ;)
254    */
255 }; // namespace
256
257 #endif