1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is [Open Source Virtual Machine].
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2004-2007
21 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #ifndef __nanojit_Containers__
41 #define __nanojit_Containers__
45 /** simple linear bit array, memory taken from Allocator
46 * warning: when bit array grows, old memory is wasted since it
47 * was allocated from Allocator. pre-size the bitmap when possible
48 * by passing nbits to the constructor. */
53 static const int64_t ONE
= 1;
54 static const int SHIFT
= 6;
56 inline int bitnum2word(int i
) {
59 inline int64_t bitnum2mask(int i
) {
60 return ONE
<< (i
& 63);
63 /** keep doubling array to fit at least w words */
67 BitSet(Allocator
& allocator
, int nbits
=128);
72 /** perform a bitwise or with BitSet other, return true if
73 * this bitset was modified */
74 bool setFrom(BitSet
& other
);
76 /** return bit i as a bool */
79 int w
= bitnum2word(i
);
81 return (bits
[w
] & bitnum2mask(i
)) != 0;
88 int w
= bitnum2word(i
);
91 bits
[w
] |= bitnum2mask(i
);
97 int w
= bitnum2word(i
);
99 bits
[w
] &= ~bitnum2mask(i
);
103 /** Seq is a single node in a linked list */
104 template<class T
> class Seq
{
106 Seq(T head
, Seq
<T
>* tail
=NULL
) : head(head
), tail(tail
) {}
111 /** SeqBuilder is used to create a linked list of Seq<T> by inserting
112 * nodes either at the beginning, with insert(), or at the end, with
113 * add(). Once built, the actual list can be retained while this
114 * SeqBuilder can be discarded. */
115 template<class T
> class SeqBuilder
{
117 SeqBuilder(Allocator
& allocator
)
118 : allocator(allocator
)
123 /** add item to beginning of list */
124 void insert(T item
) {
125 Seq
<T
>* e
= new (allocator
) Seq
<T
>(item
, items
);
131 /** add item to end of list */
133 Seq
<T
>* e
= new (allocator
) Seq
<T
>(item
);
141 /** return first item in sequence */
142 Seq
<T
>* get() const {
146 /** self explanitory */
147 bool isEmpty() const {
148 return items
== NULL
;
151 /** de-reference all items */
157 Allocator
& allocator
;
163 static inline size_t murmurhash(const void *key
, size_t len
) {
164 const uint64_t m
= 0xc6a4a7935bd1e995;
168 const uint64_t *data
= (const uint64_t*)key
;
169 const uint64_t *end
= data
+ (len
/8);
173 uint64_t k
= *data
++;
183 const unsigned char *data2
= (const unsigned char*)data
;
186 case 7: h
^= uint64_t(data2
[6]) << 48;
187 case 6: h
^= uint64_t(data2
[5]) << 40;
188 case 5: h
^= uint64_t(data2
[4]) << 32;
189 case 4: h
^= uint64_t(data2
[3]) << 24;
190 case 3: h
^= uint64_t(data2
[2]) << 16;
191 case 2: h
^= uint64_t(data2
[1]) << 8;
192 case 1: h
^= uint64_t(data2
[0]);
203 static inline size_t murmurhash(const void * key
, size_t len
) {
204 const uint32_t m
= 0x5bd1e995;
208 const unsigned char * data
= (const unsigned char *)key
;
210 uint32_t k
= *(size_t *)(void*)data
;
224 case 3: h
^= data
[2] << 16;
225 case 2: h
^= data
[1] << 8;
226 case 1: h
^= data
[0];
238 template<class K
> struct DefaultHash
{
239 static size_t hash(const K
&k
) {
240 // (const void*) cast is required by ARM RVCT 2.2
241 return murmurhash((const void*) &k
, sizeof(K
));
245 template<class K
> struct DefaultHash
<K
*> {
246 static size_t hash(K
* k
) {
247 uintptr_t h
= (uintptr_t) k
;
248 // move the low 3 bits higher up since they're often 0
249 h
= (h
>>3) ^ (h
<<((sizeof(uintptr_t) * 8) - 3));
254 /** Bucket hashtable with a fixed # of buckets (never rehash)
255 * Intended for use when a reasonable # of buckets can be estimated ahead of time.
256 * Note that operator== is used to compare keys.
258 template<class K
, class T
, class H
=DefaultHash
<K
> > class HashMap
{
259 Allocator
& allocator
;
265 Node(K k
, T v
) : key(k
), value(v
) { }
269 /** return the node containing K, and the bucket index, or NULL if not found */
270 Node
* find(K k
, size_t &i
) {
271 i
= H::hash(k
) % nbuckets
;
272 for (Seq
<Node
>* p
= buckets
[i
]; p
!= NULL
; p
= p
->tail
) {
273 if (p
->head
.key
== k
)
279 HashMap(Allocator
& a
, size_t nbuckets
= 16)
282 , buckets(new (a
) Seq
<Node
>*[nbuckets
])
284 NanoAssert(nbuckets
> 0);
288 /** clear all buckets. Since we allocate all memory from Allocator,
289 * nothing needs to be freed. */
291 VMPI_memset(buckets
, 0, sizeof(Seq
<Node
>*) * nbuckets
);
294 /** add (k,v) to the map. If k is already in the map, replace the value */
295 void put(const K
& k
, const T
& v
) {
297 Node
* n
= find(k
, i
);
302 buckets
[i
] = new (allocator
) Seq
<Node
>(Node(k
,v
), buckets
[i
]);
305 /** return v for element k, or T(0) if k is not present */
308 Node
* n
= find(k
, i
);
309 return n
? n
->value
: 0;
312 /** returns true if k is in the map. */
313 bool containsKey(const K
& k
) {
315 return find(k
, i
) != 0;
318 /** remove k from the map, if it is present. if not, remove()
319 * silently returns */
320 void remove(const K
& k
) {
321 size_t i
= H::hash(k
) % nbuckets
;
322 Seq
<Node
>** prev
= &buckets
[i
];
323 for (Seq
<Node
>* p
= buckets
[i
]; p
!= NULL
; p
= p
->tail
) {
324 if (p
->head
.key
== k
) {
332 /** Iter is an iterator for HashMap, intended to be instantiated on
333 * the stack. Iteration order is undefined. Mutating the hashmap
334 * while iteration is in progress gives undefined results. All iteration
335 * state is in class Iter, so multiple iterations can be in progress
336 * at the same time. for example:
338 * HashMap<K,T>::Iter iter(map);
339 * while (iter.next()) {
341 * T *t = iter.value();
345 friend class HashMap
;
346 const HashMap
<K
,T
,H
> &map
;
348 const Seq
<Node
>* current
;
351 Iter(HashMap
<K
,T
,H
>& map
) : map(map
), bucket((int)map
.nbuckets
-1), current(NULL
)
354 /** return true if more (k,v) remain to be visited */
357 current
= current
->tail
;
358 while (bucket
>= 0 && !current
)
359 current
= map
.buckets
[bucket
--];
360 return current
!= NULL
;
363 /** return the current key */
364 const K
& key() const {
365 NanoAssert(current
!= NULL
);
366 return current
->head
.key
;
369 /** return the current value */
370 const T
& value() const {
371 NanoAssert(current
!= NULL
);
372 return current
->head
.value
;
376 /** return true if the hashmap has no elements */
384 * Simple binary tree. No balancing is performed under the assumption
385 * that the only users of this structure are not performance critical.
387 template<class K
, class T
> class TreeMap
{
395 Node(K k
, T v
) : left(NULL
), right(NULL
), key(k
), value(v
)
401 * helper method to recursively insert (k,v) below Node n or a child
402 * of n so that the binary search tree remains well formed.
404 void insert(Node
* &n
, K k
, T v
) {
406 n
= new (alloc
) Node(k
, v
);
407 else if (k
== n
->key
)
410 insert(n
->left
, k
, v
);
412 insert(n
->right
, k
, v
);
416 * search for key k below Node n and return n if found, or the
417 * closest parent n where k should be inserted.
419 Node
* find(Node
* n
, K k
) {
425 return find(n
->left
, k
);
427 return find(n
->right
, k
);
432 TreeMap(Allocator
& alloc
) : alloc(alloc
), root(NULL
)
435 /** set k = v in the map. if k already exists, replace its value */
440 /** return the closest key that is <= k, or NULL if k
441 is smaller than every key in the Map. */
443 Node
* n
= find(root
, k
);
444 return n
? n
->key
: 0;
447 /** returns the value for k or NULL */
449 Node
* n
= find(root
, k
);
450 return (n
&& n
->key
== k
) ? n
->value
: 0;
453 /** returns true iff k is in the Map. */
454 bool containsKey(K k
) {
455 Node
* n
= find(root
, k
);
456 return n
&& n
->key
== k
;
459 /** make the tree empty. trivial since we dont manage elements */
465 #endif // __nanojit_Containers__