1 // This file is part of Freecell Solver. It is subject to the license terms in
2 // the COPYING.txt file found in the top-level directory of this distribution
3 // and at http://fc-solve.shlomifish.org/docs/distro/COPYING.html . No part of
4 // Freecell Solver, including this file, may be copied, modified, propagated,
5 // or distributed except according to the terms contained in the COPYING file.
6 //
7 // Copyright (c) 2010 Shlomi Fish
8 // google_hash.cpp - module file for Google's dense_hash_map as adapted
9 // for Freecell Solver.
10 #include "google_hash.h"
11
12 #if ((FCS_WHICH_STATES_GOOGLE_HASH == FCS_WHICH_STATES_GOOGLE_HASH__DENSE) || \
13 (FCS_WHICH_COLUMNS_GOOGLE_HASH == FCS_WHICH_COLUMNS_GOOGLE_HASH__DENSE))
14 #include <google/dense_hash_set>
15 #endif
16
17 #if ((FCS_WHICH_STATES_GOOGLE_HASH == FCS_WHICH_STATES_GOOGLE_HASH__SPARSE) || \
18 (FCS_WHICH_COLUMNS_GOOGLE_HASH == FCS_WHICH_COLUMNS_GOOGLE_HASH__SPARSE))
19 #include <google/sparse_hash_set>
20 #endif
21
22 #include "state.h"
23
24 #if ((FCS_WHICH_STATES_GOOGLE_HASH == FCS_WHICH_STATES_GOOGLE_HASH__DENSE) || \
25 (FCS_WHICH_COLUMNS_GOOGLE_HASH == FCS_WHICH_COLUMNS_GOOGLE_HASH__DENSE))
26 using google::dense_hash_set; // namespace where class lives by default
27 #endif
28
29 #if ((FCS_WHICH_STATES_GOOGLE_HASH == FCS_WHICH_STATES_GOOGLE_HASH__SPARSE) || \
30 (FCS_WHICH_COLUMNS_GOOGLE_HASH == FCS_WHICH_COLUMNS_GOOGLE_HASH__SPARSE))
31 using google::sparse_hash_set; // namespace where class lives by default
32 #endif
33
34 typedef unsigned long int ub4; // unsigned 4+ bytes quantities
35 typedef unsigned char ub1;
36
perl_hash_function(register const ub1 * s_ptr,register const ub4 length)37 static inline ub4 perl_hash_function(
38 register const ub1 *s_ptr, register const ub4 length)
39 {
40 register ub4 hash_value_int = 0;
41 register const ub1 *s_end = s_ptr + length;
42
43 while (s_ptr < s_end)
44 {
45 hash_value_int += (hash_value_int << 5) + *(s_ptr++);
46 }
47 hash_value_int += (hash_value_int >> 5);
48
49 return hash_value_int;
50 }
51
52 #if (FCS_STATE_STORAGE == FCS_STATE_STORAGE_GOOGLE_DENSE_HASH)
53
54 struct state_equality
55 {
operator ()state_equality56 bool operator()(const char *s1, const char *s2) const
57 {
58 return (s1 == s2) ||
59 (s1 && s2 && (fc_solve_state_compare(s1, s2) == 0));
60 }
61 };
62
63 struct state_hash
64 {
operator ()state_hash65 int operator()(const char *s1) const
66 {
67 return perl_hash_function((const ub1 *)s1, sizeof(fcs_state));
68 }
69 };
70
71 #if (FCS_WHICH_STATES_GOOGLE_HASH == FCS_WHICH_STATES_GOOGLE_HASH__SPARSE)
72 typedef sparse_hash_set<char *, state_hash, state_equality> StatesGoogleHash;
73 #else
74 typedef dense_hash_set<char *, state_hash, state_equality> StatesGoogleHash;
75 #endif
76
fc_solve_states_google_hash_new()77 extern "C" fcs_states_google_hash_handle fc_solve_states_google_hash_new()
78 {
79 static fcs_state deleted_key = {0};
80 StatesGoogleHash *ret = new StatesGoogleHash;
81
82 #if (FCS_WHICH_STATES_GOOGLE_HASH == FCS_WHICH_STATES_GOOGLE_HASH__DENSE)
83 ret->set_empty_key(NULL);
84 #endif
85 ret->set_deleted_key((char *)&deleted_key);
86
87 return (fcs_states_google_hash_handle)(ret);
88 }
89
90 // Returns 0 if the key is new and the key/val pair was inserted.
91 // - in that case *existing_key / *existing_val will be set to key
92 // and val respectively.
93 // Returns 1 if the key is not new and *existing_key / *existing_val
94 // was set to it.
fc_solve_states_google_hash_insert(fcs_states_google_hash_handle void_hash,void * key,void ** existing_key)95 extern "C" bool fc_solve_states_google_hash_insert(
96 fcs_states_google_hash_handle void_hash, void *key, void **existing_key)
97 {
98 StatesGoogleHash *hash = (StatesGoogleHash *)void_hash;
99 std::pair<StatesGoogleHash::iterator, bool> result =
100 hash->insert((char *)key);
101
102 // If an insertion took place.
103 if (result.second)
104 {
105 *existing_key = NULL;
106 return false;
107 }
108 else
109 {
110 *existing_key = (*(result.first));
111
112 return true;
113 }
114 }
115
fc_solve_states_google_hash_free(fcs_states_google_hash_handle void_hash)116 extern "C" void fc_solve_states_google_hash_free(
117 fcs_states_google_hash_handle void_hash)
118 {
119 StatesGoogleHash *hash = (StatesGoogleHash *)void_hash;
120
121 delete hash;
122
123 return;
124 }
125
fc_solve_states_google_hash_foreach(fcs_states_google_hash_handle void_hash,bool (* should_delete_ptr)(void * key,void * context),void * context)126 extern void fc_solve_states_google_hash_foreach(
127 fcs_states_google_hash_handle void_hash,
128 bool (*should_delete_ptr)(void *key, void *context), void *context)
129 {
130 StatesGoogleHash *hash = (StatesGoogleHash *)void_hash;
131
132 for (StatesGoogleHash::iterator it = hash->begin(); it != hash->end(); ++it)
133 {
134 if (should_delete_ptr(*(it), context))
135 {
136 hash->erase(it);
137 }
138 }
139 }
140
141 #endif
142
143 #if (FCS_STACK_STORAGE == FCS_STACK_STORAGE_GOOGLE_DENSE_HASH)
144
145 struct column_equality
146 {
operator ()column_equality147 bool operator()(const char *s1, const char *s2) const
148 {
149 return (s1 == s2) ||
150 (s1 && s2 &&
151 (fc_solve_stack_compare_for_comparison(s1, s2) == 0));
152 }
153 };
154
155 struct column_hash
156 {
operator ()column_hash157 int operator()(const char *s1) const
158 {
159 return perl_hash_function((const ub1 *)s1, fcs_col_len(s1) + 1);
160 }
161 };
162
163 #if (FCS_WHICH_COLUMNS_GOOGLE_HASH == FCS_WHICH_COLUMNS_GOOGLE_HASH__SPARSE)
164 typedef sparse_hash_set<char *, column_hash, column_equality> ColumnsGoogleHash;
165 #else
166 typedef dense_hash_set<char *, column_hash, column_equality> ColumnsGoogleHash;
167 #endif
168
fc_solve_columns_google_hash_new()169 extern "C" fcs_columns_google_hash_handle fc_solve_columns_google_hash_new()
170 {
171 static char deleted_key[3] = "\xFF\xFF";
172 ColumnsGoogleHash *ret = new ColumnsGoogleHash;
173
174 #if (FCS_WHICH_STATES_GOOGLE_HASH == FCS_WHICH_COLUMNS_GOOGLE_HASH__DENSE)
175 ret->set_empty_key(NULL);
176 #endif
177 ret->set_deleted_key(deleted_key);
178
179 return (fcs_columns_google_hash_handle)(ret);
180 }
181
182 // Returns 0 if the key is new and the key/val pair was inserted.
183 // - in that case *existing_key / *existing_val will be set to key
184 // and val respectively.
185 // Returns 1 if the key is not new and *existing_key / *existing_val
186 // was set to it.
fc_solve_columns_google_hash_insert(fcs_columns_google_hash_handle void_hash,void * key,void ** existing_key)187 extern "C" bool fc_solve_columns_google_hash_insert(
188 fcs_columns_google_hash_handle void_hash, void *key, void **existing_key)
189 {
190 ColumnsGoogleHash *hash = (ColumnsGoogleHash *)void_hash;
191 std::pair<ColumnsGoogleHash::iterator, bool> result =
192 hash->insert((char *)key);
193
194 // If an insertion took place.
195 if (result.second)
196 {
197 *existing_key = NULL;
198 return false;
199 }
200 else
201 {
202 *existing_key = (*(result.first));
203
204 return true;
205 }
206 }
207
fc_solve_columns_google_hash_free(fcs_columns_google_hash_handle void_hash)208 extern "C" void fc_solve_columns_google_hash_free(
209 fcs_columns_google_hash_handle void_hash)
210 {
211 ColumnsGoogleHash *hash = (ColumnsGoogleHash *)void_hash;
212
213 delete hash;
214
215 return;
216 }
217
218 #endif
219