hash-list-inl.h
Go to the documentation of this file.
1 // util/hash-list-inl.h
2 
3 // Copyright 2009-2011 Microsoft Corporation
4 // 2013 Johns Hopkins University (author: Daniel Povey)
5 
6 // See ../../COPYING for clarification regarding multiple authors
7 //
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
11 //
12 // http://www.apache.org/licenses/LICENSE-2.0
13 //
14 // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 // MERCHANTABLITY OR NON-INFRINGEMENT.
18 // See the Apache 2 License for the specific language governing permissions and
19 // limitations under the License.
20 
21 
22 #ifndef KALDI_UTIL_HASH_LIST_INL_H_
23 #define KALDI_UTIL_HASH_LIST_INL_H_
24 
25 // Do not include this file directly. It is included by fast-hash.h
26 
27 
28 namespace kaldi {
29 
30 template<class I, class T> HashList<I, T>::HashList() {
31  list_head_ = NULL;
32  bucket_list_tail_ = static_cast<size_t>(-1); // invalid.
33  hash_size_ = 0;
34  freed_head_ = NULL;
35 }
36 
37 template<class I, class T> void HashList<I, T>::SetSize(size_t size) {
38  hash_size_ = size;
39  KALDI_ASSERT(list_head_ == NULL &&
40  bucket_list_tail_ == static_cast<size_t>(-1)); // make sure empty.
41  if (size > buckets_.size())
42  buckets_.resize(size, HashBucket(0, NULL));
43 }
44 
45 template<class I, class T>
47  // Clears the hashtable and gives ownership of the currently contained list
48  // to the user.
49  for (size_t cur_bucket = bucket_list_tail_;
50  cur_bucket != static_cast<size_t>(-1);
51  cur_bucket = buckets_[cur_bucket].prev_bucket) {
52  buckets_[cur_bucket].last_elem = NULL; // this is how we indicate "empty".
53  }
54  bucket_list_tail_ = static_cast<size_t>(-1);
55  Elem *ans = list_head_;
56  list_head_ = NULL;
57  return ans;
58 }
59 
60 template<class I, class T>
62  return list_head_;
63 }
64 
65 template<class I, class T>
66 inline void HashList<I, T>::Delete(Elem *e) {
67  e->tail = freed_head_;
68  freed_head_ = e;
69 }
70 
71 template<class I, class T>
72 inline typename HashList<I, T>::Elem* HashList<I, T>::Find(I key) {
73  size_t index = (static_cast<size_t>(key) % hash_size_);
74  HashBucket &bucket = buckets_[index];
75  if (bucket.last_elem == NULL) {
76  return NULL; // empty bucket.
77  } else {
78  Elem *head = (bucket.prev_bucket == static_cast<size_t>(-1) ?
79  list_head_ :
80  buckets_[bucket.prev_bucket].last_elem->tail),
81  *tail = bucket.last_elem->tail;
82  for (Elem *e = head; e != tail; e = e->tail)
83  if (e->key == key) return e;
84  return NULL; // Not found.
85  }
86 }
87 
88 template<class I, class T>
90  if (freed_head_) {
91  Elem *ans = freed_head_;
92  freed_head_ = freed_head_->tail;
93  return ans;
94  } else {
95  Elem *tmp = new Elem[allocate_block_size_];
96  for (size_t i = 0; i+1 < allocate_block_size_; i++)
97  tmp[i].tail = tmp+i+1;
98  tmp[allocate_block_size_-1].tail = NULL;
99  freed_head_ = tmp;
100  allocated_.push_back(tmp);
101  return this->New();
102  }
103 }
104 
105 template<class I, class T>
107  // First test whether we had any memory leak within the
108  // HashList, i.e. things for which the user did not call Delete().
109  size_t num_in_list = 0, num_allocated = 0;
110  for (Elem *e = freed_head_; e != NULL; e = e->tail)
111  num_in_list++;
112  for (size_t i = 0; i < allocated_.size(); i++) {
113  num_allocated += allocate_block_size_;
114  delete[] allocated_[i];
115  }
116  if (num_in_list != num_allocated) {
117  KALDI_WARN << "Possible memory leak: " << num_in_list
118  << " != " << num_allocated
119  << ": you might have forgotten to call Delete on "
120  << "some Elems";
121  }
122 }
123 
124 template<class I, class T>
125 inline typename HashList<I, T>::Elem* HashList<I, T>::Insert(I key, T val) {
126  size_t index = (static_cast<size_t>(key) % hash_size_);
127  HashBucket &bucket = buckets_[index];
128  // Check the element is existing or not.
129  if (bucket.last_elem != NULL) {
130  Elem *head = (bucket.prev_bucket == static_cast<size_t>(-1) ?
131  list_head_ :
132  buckets_[bucket.prev_bucket].last_elem->tail),
133  *tail = bucket.last_elem->tail;
134  for (Elem *e = head; e != tail; e = e->tail)
135  if (e->key == key) return e;
136  }
137 
138  // This is a new element. Insert it.
139  Elem *elem = New();
140  elem->key = key;
141  elem->val = val;
142  if (bucket.last_elem == NULL) { // Unoccupied bucket. Insert at
143  // head of bucket list (which is tail of regular list, they go in
144  // opposite directions).
145  if (bucket_list_tail_ == static_cast<size_t>(-1)) {
146  // list was empty so this is the first elem.
147  KALDI_ASSERT(list_head_ == NULL);
148  list_head_ = elem;
149  } else {
150  // link in to the chain of Elems
151  buckets_[bucket_list_tail_].last_elem->tail = elem;
152  }
153  elem->tail = NULL;
154  bucket.last_elem = elem;
155  bucket.prev_bucket = bucket_list_tail_;
156  bucket_list_tail_ = index;
157  } else {
158  // Already-occupied bucket. Insert at tail of list of elements within
159  // the bucket.
160  elem->tail = bucket.last_elem->tail;
161  bucket.last_elem->tail = elem;
162  bucket.last_elem = elem;
163  }
164  return elem;
165 }
166 
167 template<class I, class T>
168 void HashList<I, T>::InsertMore(I key, T val) {
169  size_t index = (static_cast<size_t>(key) % hash_size_);
170  HashBucket &bucket = buckets_[index];
171  Elem *elem = New();
172  elem->key = key;
173  elem->val = val;
174 
175  KALDI_ASSERT(bucket.last_elem != NULL); // assume one element is already here
176  if (bucket.last_elem->key == key) { // standard behavior: add as last element
177  elem->tail = bucket.last_elem->tail;
178  bucket.last_elem->tail = elem;
179  bucket.last_elem = elem;
180  return;
181  }
182  Elem *e = (bucket.prev_bucket == static_cast<size_t>(-1) ?
183  list_head_ : buckets_[bucket.prev_bucket].last_elem->tail);
184  // find place to insert in linked list
185  while (e != bucket.last_elem->tail && e->key != key) e = e->tail;
186  KALDI_ASSERT(e->key == key); // not found? - should not happen
187  elem->tail = e->tail;
188  e->tail = elem;
189 }
190 
191 
192 } // end namespace kaldi
193 
194 #endif // KALDI_UTIL_HASH_LIST_INL_H_
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
Elem * Insert(I key, T val)
Insert inserts a new element into the hashtable/stored list.
HashList()
Constructor takes no arguments.
Definition: hash-list-inl.h:30
void SetSize(size_t sz)
SetSize tells the object how many hash buckets to allocate (should typically be at least twice the nu...
Definition: hash-list-inl.h:37
const Elem * GetList() const
Gives the head of the current list to the user.
Definition: hash-list-inl.h:61
#define KALDI_WARN
Definition: kaldi-error.h:150
Elem * Clear()
Clears the hash and gives the head of the current list to the user; ownership is transferred to the u...
Definition: hash-list-inl.h:46
Elem * New()
This should probably not be needed to be called directly by the user.
Definition: hash-list-inl.h:89
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
void InsertMore(I key, T val)
Insert inserts another element with same key into the hashtable/ stored list.
Elem * Find(I key)
Find tries to find this element in the current list using the hashtable.
Definition: hash-list-inl.h:72
void Delete(Elem *e)
Think of this like delete().
Definition: hash-list-inl.h:66