source: GTP/trunk/Lib/Vis/Preprocessing/src/sparsehash/src/sparsetable_unittest.cc @ 2162

Revision 2162, 11.7 KB checked in by mattausch, 17 years ago (diff)

improved hash performance with google hashmap

Line 
1// Copyright (c) 2005, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14//     * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// ---
31// Author: Craig Silverstein
32//
33// This tests <google/sparsetable>
34//
35// Since sparsetable is templatized, it's important that we test every
36// function in every class in this file -- not just to see if it
37// works, but even if it compiles.
38
39#include <google/sparsehash/config.h>
40#include <string>
41#include <stdio.h>
42#include <string.h>         // for memcmp()
43#include <stdlib.h>         // defines unlink() on some windows platforms(?)
44#ifdef HAVE_UNISTD_H
45#include <unistd.h>         // for unlink()
46#endif
47#include <google/sparsetable>
48
49using STL_NAMESPACE::string;
50
51// Many sparsetable operations return a size_t.  Unfortunately, there's
52// no portable way to pass a size_t to snprintf().  This macro casts these
53// things to an unsigned long, which should be big enough for a size_t.
54#define UL(x)    ( static_cast<unsigned long>(x) )
55
56
57static char outbuf[10240];       // big enough for these tests
58static char* out = outbuf;       // where to write next
59#define LEFT (outbuf + sizeof(outbuf) - out)
60
61#define TEST(cond)  out += snprintf(out, LEFT, #cond "? %s\n", \
62                                    cond ? "yes" : "no");
63
64using GOOGLE_NAMESPACE::sparsetable;
65
66// replaces buf, in-place, with a version of buf that lacks \r's.
67static int strip_cr(char* buf, int len) {
68  char *r, *w;
69  for ( r = buf, w = buf; r - buf < len; r++ ) {
70    if (*r != '\r')
71      *w++ = *r;
72  }
73  return w - buf;
74}
75
76int main(int argc, char **argv) {          // though we ignore the args
77  sparsetable<int> x(7), y(70), z;
78  x.set(4, 10);
79  y.set(12, -12);
80  y.set(47, -47);
81  y.set(48, -48);
82  y.set(49, -49);
83
84  const sparsetable<int> constx(x);
85  const sparsetable<int> consty(y);
86
87  // ----------------------------------------------------------------------
88  // Test the plain iterators
89
90  for ( sparsetable<int>::iterator it = x.begin(); it != x.end(); ++it ) {
91    out += snprintf(out, LEFT, "x[%lu]: %d\n", UL(it - x.begin()), int(*it));
92  }
93  for ( sparsetable<int>::const_iterator it = x.begin(); it != x.end(); ++it ) {
94    out += snprintf(out, LEFT, "x[%lu]: %d\n", UL(it - x.begin()), *it);
95  }
96  for ( sparsetable<int>::reverse_iterator it = x.rbegin(); it != x.rend(); ++it ) {
97    out += snprintf(out, LEFT, "x[%lu]: %d\n", UL(x.rend()-1 - it), int(*it));
98  }
99  for ( sparsetable<int>::const_reverse_iterator it = constx.rbegin(); it != constx.rend(); ++it ) {
100    out += snprintf(out, LEFT, "x[%lu]: %d\n", UL(constx.rend()-1 - it), *it);
101  }
102  for ( sparsetable<int>::iterator it = z.begin(); it != z.end(); ++it ) {
103    out += snprintf(out, LEFT, "z[%lu]: %d\n", UL(it - z.begin()), int(*it));
104  }
105
106  {                                          // array version
107    out += snprintf(out, LEFT, "x[3]: %d\n", int(x[3]));
108    out += snprintf(out, LEFT, "x[4]: %d\n", int(x[4]));
109    out += snprintf(out, LEFT, "x[5]: %d\n", int(x[5]));
110  }
111  {
112    sparsetable<int>::iterator it;           // non-const version
113    out += snprintf(out, LEFT, "x[4]: %d\n", int(x.begin()[4]));
114    it = x.begin() + 4;          // should point to the non-zero value
115    out += snprintf(out, LEFT, "x[4]: %d\n", int(*it));
116    it--;
117    --it;
118    it += 5;
119    it -= 2;
120    it++;
121    ++it;
122    it = it - 3;
123    it = 1 + it;                 // now at 5
124    out += snprintf(out, LEFT, "x[3]: %d\n", int(it[-2]));
125    out += snprintf(out, LEFT, "x[4]: %d\n", int(it[-1]));
126    *it = 55;
127    out += snprintf(out, LEFT, "x[5]: %d\n", int(it[0]));
128    out += snprintf(out, LEFT, "x[5]: %d\n", int(*it));
129    int *x6 = &(it[1]);
130    *x6 = 66;
131    out += snprintf(out, LEFT, "x[6]: %d\n", int(*(it + 1)));
132  }
133  {
134    sparsetable<int>::const_iterator it;    // const version
135    out += snprintf(out, LEFT, "x[4]: %d\n", int(x.begin()[4]));
136    it = x.begin() + 4;          // should point to the non-zero value
137    out += snprintf(out, LEFT, "x[4]: %d\n", *it);
138    it--;
139    --it;
140    it += 5;
141    it -= 2;
142    it++;
143    ++it;
144    it = it - 3;
145    it = 1 + it;                 // now at 5
146    out += snprintf(out, LEFT, "x[3]: %d\n", it[-2]);
147    out += snprintf(out, LEFT, "x[4]: %d\n", it[-1]);
148    out += snprintf(out, LEFT, "x[5]: %d\n", *it);
149    out += snprintf(out, LEFT, "x[6]: %d\n", *(it + 1));
150  }
151
152  TEST(x.begin() == x.begin() + 1 - 1);
153  TEST(x.begin() < x.end());
154  TEST(z.begin() < z.end());
155  TEST(z.begin() <= z.end());
156  TEST(z.begin() == z.end());
157
158
159  // ----------------------------------------------------------------------
160  // Test the non-empty iterators
161
162  for ( sparsetable<int>::nonempty_iterator it = x.nonempty_begin(); it != x.nonempty_end(); ++it ) {
163    out += snprintf(out, LEFT, "x[??]: %d\n", *it);
164  }
165  for ( sparsetable<int>::const_nonempty_iterator it = y.nonempty_begin(); it != y.nonempty_end(); ++it ) {
166    out += snprintf(out, LEFT, "y[??]: %d\n", *it);
167  }
168  for ( sparsetable<int>::reverse_nonempty_iterator it = y.nonempty_rbegin(); it != y.nonempty_rend(); ++it ) {
169    out += snprintf(out, LEFT, "y[??]: %d\n", *it);
170  }
171  for ( sparsetable<int>::const_reverse_nonempty_iterator it = consty.nonempty_rbegin(); it != consty.nonempty_rend(); ++it ) {
172    out += snprintf(out, LEFT, "y[??]: %d\n", *it);
173  }
174  for ( sparsetable<int>::nonempty_iterator it = z.nonempty_begin(); it != z.nonempty_end(); ++it ) {
175    out += snprintf(out, LEFT, "z[??]: %d\n", *it);
176  }
177
178  {
179    sparsetable<int>::nonempty_iterator it;           // non-const version
180    out += snprintf(out, LEFT, "first non-empty y: %d\n", *y.nonempty_begin());
181    out += snprintf(out, LEFT, "first non-empty x: %d\n", *x.nonempty_begin());
182    it = x.nonempty_begin();
183    ++it;                        // should be at end
184    --it;
185    out += snprintf(out, LEFT, "first non-empty x: %d\n", *it++);
186    it--;
187    out += snprintf(out, LEFT, "first non-empty x: %d\n", *it++);
188  }
189  {
190    sparsetable<int>::const_nonempty_iterator it;           // non-const version
191    out += snprintf(out, LEFT, "first non-empty y: %d\n", *y.nonempty_begin());
192    out += snprintf(out, LEFT, "first non-empty x: %d\n", *x.nonempty_begin());
193    it = x.nonempty_begin();
194    ++it;                        // should be at end
195    --it;
196    out += snprintf(out, LEFT, "first non-empty x: %d\n", *it++);
197    it--;
198    out += snprintf(out, LEFT, "first non-empty x: %d\n", *it++);
199  }
200
201  TEST(x.begin() == x.begin() + 1 - 1);
202  TEST(z.begin() != z.end());
203
204  // ----------------------------------------------------------------------
205  // Test sparsetable functions
206  out += snprintf(out, LEFT, "x has %lu/%lu buckets, "
207                  "y %lu/%lu, z %lu/%lu\n",
208                  UL(x.num_nonempty()), UL(x.size()),
209                  UL(y.num_nonempty()), UL(y.size()),
210                  UL(z.num_nonempty()), UL(z.size()));
211 
212  y.resize(48);              // should get rid of 48 and 49
213  y.resize(70);              // 48 and 49 should still be gone
214  out += snprintf(out, LEFT, "y shrank and grew: it's now %lu/%lu\n",
215                  UL(y.num_nonempty()), UL(y.size()));
216  out += snprintf(out, LEFT, "y[12] = %d, y.get(12) = %d\n", int(y[12]), y.get(12));
217  y.erase(12);
218  out += snprintf(out, LEFT, "y[12] cleared.  y now %lu/%lu.  "
219                  "y[12] = %d, y.get(12) = %d\n",
220                  UL(y.num_nonempty()), UL(y.size()), int(y[12]), y.get(12));
221
222  swap(x, y);
223
224  y.clear();
225  TEST(y == z);
226
227  y.resize(70);
228  for ( int i = 10; i < 40; ++i )
229    y[i] = -i;
230  y.erase(y.begin() + 15, y.begin() + 30);
231  y.erase(y.begin() + 34);
232  y.erase(12);
233  y.resize(38);
234  y.resize(10000);
235  y[9898] = -9898;
236  for ( sparsetable<int>::const_iterator it = y.begin(); it != y.end(); ++it ) {
237    if ( y.test(it) )
238      out += snprintf(out, LEFT, "y[%lu] is set\n", UL(it - y.begin()));
239  }
240  out += snprintf(out, LEFT, "That's %lu set buckets\n", UL(y.num_nonempty()));
241
242  out += snprintf(out, LEFT, "Starting from y[32]...\n");
243  for ( sparsetable<int>::const_nonempty_iterator it = y.get_iter(32);
244        it != y.nonempty_end(); ++it )
245    out += snprintf(out, LEFT, "y[??] = %d\n", *it);
246
247  out += snprintf(out, LEFT, "From y[32] down...\n");
248  for ( sparsetable<int>::nonempty_iterator it = y.get_iter(32);
249        it != y.nonempty_begin(); )
250    out += snprintf(out, LEFT, "y[??] = %d\n", *--it);
251
252  // ----------------------------------------------------------------------
253  // Test I/O
254  const char *file = "/tmp/#sparsetable.test";
255  FILE *fp = fopen(file, "wb");
256  if ( fp == NULL ) {
257    // maybe we can't write to /tmp/.  Try the current directory
258    file = "#sparsetable.test";
259    fp = fopen(file, "wb");
260  }
261  if ( fp == NULL ) {
262    out += snprintf(out, LEFT, "Can't open %s, skipping disk write...\n", file);
263  } else {
264    y.write_metadata(fp);          // only write meta-information
265    y.write_nopointer_data(fp);
266    fclose(fp);
267  }
268  fp = fopen(file, "rb");
269  if ( fp == NULL ) {
270    out += snprintf(out, LEFT, "Can't open %s, skipping disk read...\n", file);
271  } else {
272    sparsetable<int> y2;
273    y2.read_metadata(fp);
274    y2.read_nopointer_data(fp);
275    fclose(fp);
276
277    for ( sparsetable<int>::const_iterator it = y2.begin(); it != y2.end(); ++it ) {
278      if ( y2.test(it) )
279        out += snprintf(out, LEFT, "y2[%lu] is %d\n", UL(it - y2.begin()), *it);
280    }
281    out += snprintf(out, LEFT, "That's %lu set buckets\n", UL(y2.num_nonempty()));
282  }
283  unlink(file);
284
285  // Finally, check to see if our output (in out) is what it's supposed to be.
286  char expected[sizeof(outbuf) + 10];
287  string filename = (string(getenv("srcdir") ? getenv("srcdir") : ".") +
288                     "/src/sparsetable_unittest.expected");
289  FILE* expected_fp = fopen(filename.c_str(), "rb");
290  if ( expected_fp == NULL ) {
291    fprintf(stderr, "Can't judge test: can't load 'golden' file '%s'.\n",
292            filename.c_str());
293    return 2;
294  }
295  int r = fread(expected, 1, sizeof(expected) - 1, expected_fp);
296  r = strip_cr(expected, r);
297  if ( r != out - outbuf ||             // output not the same size
298       memcmp(outbuf, expected, r) ) {  // or bytes differed
299    fprintf(stderr, "TESTS FAILED\n\nEXPECTED:\n\n%s\n\nACTUAL:\n\n%s\n\n",
300            expected, outbuf);
301    return 1;
302  } else {
303    printf("All tests passed.\n");
304    return 0;
305  }
306}
Note: See TracBrowser for help on using the repository browser.