1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-07-04 23:36:00 +02:00

Initial checkin

This commit is contained in:
Brian Fiete 2019-08-23 11:56:54 -07:00
parent c74712dad9
commit 078564ac9e
3242 changed files with 1616395 additions and 0 deletions

View file

@ -0,0 +1,131 @@
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Namespace for Google classes */
#undef GOOGLE_NAMESPACE
/* the location of the header defining hash functions */
#undef HASH_FUN_H
/* the location of <unordered_map> or <hash_map> */
#undef HASH_MAP_H
/* the namespace of the hash<> function */
#undef HASH_NAMESPACE
/* the location of <unordered_set> or <hash_set> */
#undef HASH_SET_H
/* Define to 1 if you have the <google/malloc_extension.h> header file. */
#undef HAVE_GOOGLE_MALLOC_EXTENSION_H
/* define if the compiler has hash_map */
#undef HAVE_HASH_MAP
/* define if the compiler has hash_set */
#undef HAVE_HASH_SET
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if the system has the type `long long'. */
#undef HAVE_LONG_LONG
/* Define to 1 if you have the `memcpy' function. */
#undef HAVE_MEMCPY
/* Define to 1 if you have the `memmove' function. */
#undef HAVE_MEMMOVE
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* define if the compiler implements namespaces */
#undef HAVE_NAMESPACES
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/utsname.h> header file. */
#undef HAVE_SYS_UTSNAME_H
/* Define to 1 if the system has the type `uint16_t'. */
#undef HAVE_UINT16_T
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* define if the compiler supports unordered_{map,set} */
#undef HAVE_UNORDERED_MAP
/* Define to 1 if the system has the type `u_int16_t'. */
#undef HAVE_U_INT16_T
/* Define to 1 if the system has the type `__uint16'. */
#undef HAVE___UINT16
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
/* The system-provided hash function including the namespace. */
#undef SPARSEHASH_HASH
/* The system-provided hash function, in namespace HASH_NAMESPACE. */
#undef SPARSEHASH_HASH_NO_NAMESPACE
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Version number of package */
#undef VERSION
/* Stops putting the code inside the Google namespace */
#undef _END_GOOGLE_NAMESPACE_
/* Puts following code inside the Google namespace */
#undef _START_GOOGLE_NAMESPACE_

View file

@ -0,0 +1,22 @@
/***
*** These are #defines that autoheader puts in config.h.in that we
*** want to show up in sparseconfig.h, the minimal config.h file
*** #included by all our .h files. The reason we don't take
*** everything that autoheader emits is that we have to include a
*** config.h in installed header files, and we want to minimize the
*** number of #defines we make so as to not pollute the namespace.
***/
GOOGLE_NAMESPACE
HASH_NAMESPACE
HASH_FUN_H
SPARSEHASH_HASH
HAVE_UINT16_T
HAVE_U_INT16_T
HAVE___UINT16
HAVE_LONG_LONG
HAVE_SYS_TYPES_H
HAVE_STDINT_H
HAVE_INTTYPES_H
HAVE_MEMCPY
_END_GOOGLE_NAMESPACE_
_START_GOOGLE_NAMESPACE_

View file

@ -0,0 +1,34 @@
// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files have moved from the google directory to the sparsehash
// directory. This forwarding file is provided only for backwards
// compatibility. Use <sparsehash/*> in all new code.
#include <sparsehash/dense_hash_map>

View file

@ -0,0 +1,34 @@
// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files have moved from the google directory to the sparsehash
// directory. This forwarding file is provided only for backwards
// compatibility. Use <sparsehash/*> in all new code.
#include <sparsehash/dense_hash_set>

View file

@ -0,0 +1,34 @@
// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files have moved from the google directory to the sparsehash
// directory. This forwarding file is provided only for backwards
// compatibility. Use <sparsehash/*> in all new code.
#include <sparsehash/sparse_hash_map>

View file

@ -0,0 +1,34 @@
// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files have moved from the google directory to the sparsehash
// directory. This forwarding file is provided only for backwards
// compatibility. Use <sparsehash/*> in all new code.
#include <sparsehash/sparse_hash_set>

View file

@ -0,0 +1,35 @@
// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files have moved from the google directory to the sparsehash
// directory. This forwarding file is provided only for backwards
// compatibility. Use <sparsehash/*> in all new code.
#include <sparsehash/internal/densehashtable.h>

View file

@ -0,0 +1,34 @@
// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files have moved from the google directory to the sparsehash
// directory. This forwarding file is provided only for backwards
// compatibility. Use <sparsehash/*> in all new code.
#include <sparsehash/internal/hashtable-common.h>

View file

@ -0,0 +1,34 @@
// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files have moved from the google directory to the sparsehash
// directory. This forwarding file is provided only for backwards
// compatibility. Use <sparsehash/*> in all new code.
#include <sparsehash/internal/libc_allocator_with_realloc.h>

View file

@ -0,0 +1,34 @@
// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files have moved from the google directory to the sparsehash
// directory. This forwarding file is provided only for backwards
// compatibility. Use <sparsehash/*> in all new code.
#include <sparsehash/internal/sparsehashtable.h>

View file

@ -0,0 +1,34 @@
// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files have moved from the google directory to the sparsehash
// directory. This forwarding file is provided only for backwards
// compatibility. Use <sparsehash/*> in all new code.
#include <sparsehash/sparsetable>

View file

@ -0,0 +1,34 @@
// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files have moved from the google directory to the sparsehash
// directory. This forwarding file is provided only for backwards
// compatibility. Use <sparsehash/*> in all new code.
#include <sparsehash/template_util.h>

View file

@ -0,0 +1,34 @@
// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files have moved from the google directory to the sparsehash
// directory. This forwarding file is provided only for backwards
// compatibility. Use <sparsehash/*> in all new code.
#include <sparsehash/type_traits.h>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,122 @@
// Copyright (c) 2010, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
#include <sparsehash/internal/sparseconfig.h>
#include <config.h>
#include <sparsehash/internal/libc_allocator_with_realloc.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include "testutil.h"
using std::cerr;
using std::cout;
using std::string;
using std::basic_string;
using std::char_traits;
using std::vector;
using GOOGLE_NAMESPACE::libc_allocator_with_realloc;
#define arraysize(a) ( sizeof(a) / sizeof(*(a)) )
namespace {
typedef libc_allocator_with_realloc<int> int_alloc;
typedef int_alloc::rebind<int*>::other intp_alloc;
// cstring allocates from libc_allocator_with_realloc.
typedef basic_string<char, char_traits<char>,
libc_allocator_with_realloc<char> > cstring;
typedef vector<cstring, libc_allocator_with_realloc<cstring> > cstring_vector;
TEST(LibcAllocatorWithReallocTest, Allocate) {
int_alloc alloc;
intp_alloc palloc;
int** parray = palloc.allocate(1024);
for (int i = 0; i < 16; ++i) {
parray[i] = alloc.allocate(i * 1024 + 1);
}
for (int i = 0; i < 16; ++i) {
alloc.deallocate(parray[i], i * 1024 + 1);
}
palloc.deallocate(parray, 1024);
int* p = alloc.allocate(4096);
p[0] = 1;
p[1023] = 2;
p[4095] = 3;
p = alloc.reallocate(p, 8192);
EXPECT_EQ(1, p[0]);
EXPECT_EQ(2, p[1023]);
EXPECT_EQ(3, p[4095]);
p = alloc.reallocate(p, 1024);
EXPECT_EQ(1, p[0]);
EXPECT_EQ(2, p[1023]);
alloc.deallocate(p, 1024);
}
TEST(LibcAllocatorWithReallocTest, TestSTL) {
// Test strings copied from base/arena_unittest.cc
static const char* test_strings[] = {
"aback", "abaft", "abandon", "abandoned", "abandoning",
"abandonment", "abandons", "abase", "abased", "abasement",
"abasements", "abases", "abash", "abashed", "abashes", "abashing",
"abasing", "abate", "abated", "abatement", "abatements", "abater",
"abates", "abating", "abbe", "abbey", "abbeys", "abbot", "abbots",
"abbreviate", "abbreviated", "abbreviates", "abbreviating",
"abbreviation", "abbreviations", "abdomen", "abdomens", "abdominal",
"abduct", "abducted", "abduction", "abductions", "abductor", "abductors",
"abducts", "Abe", "abed", "Abel", "Abelian", "Abelson", "Aberdeen",
"Abernathy", "aberrant", "aberration", "aberrations", "abet", "abets",
"abetted", "abetter", "abetting", "abeyance", "abhor", "abhorred",
"abhorrent", "abhorrer", "abhorring", "abhors", "abide", "abided",
"abides", "abiding"};
cstring_vector v;
for (size_t i = 0; i < arraysize(test_strings); ++i) {
v.push_back(test_strings[i]);
}
for (size_t i = arraysize(test_strings); i > 0; --i) {
EXPECT_EQ(cstring(test_strings[i-1]), v.back());
v.pop_back();
}
}
} // namespace
int main(int, char **) {
// All the work is done in the static constructors. If they don't
// die, the tests have all passed.
cout << "PASS\n";
return 0;
}

View file

@ -0,0 +1,106 @@
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
//
// This tests mostly that we can #include the files correctly
// and have them work. It is like simple_test.cc but uses the
// compatibility #include directory (google/) rather than the
// canonical one (sparsehash/). This unittest purposefully does
// not #include <config.h>; it's meant to emulate what a 'regular
// install' of sparsehash would be able to see.
#include <stdio.h>
#include <google/sparse_hash_set>
#include <google/sparse_hash_map>
#include <google/dense_hash_set>
#include <google/dense_hash_map>
#include <google/template_util.h>
#include <google/type_traits.h>
#define CHECK_IFF(cond, when) do { \
if (when) { \
if (!(cond)) { \
puts("ERROR: " #cond " failed when " #when " is true\n"); \
exit(1); \
} \
} else { \
if (cond) { \
puts("ERROR: " #cond " succeeded when " #when " is false\n"); \
exit(1); \
} \
} \
} while (0)
int main(int argc, char**) {
// Run with an argument to get verbose output
const bool verbose = argc > 1;
google::sparse_hash_set<int> sset;
google::sparse_hash_map<int, int> smap;
google::dense_hash_set<int> dset;
google::dense_hash_map<int, int> dmap;
dset.set_empty_key(-1);
dmap.set_empty_key(-1);
for (int i = 0; i < 100; i += 10) { // go by tens
sset.insert(i);
smap[i] = i+1;
dset.insert(i + 5);
dmap[i+5] = i+6;
}
if (verbose) {
for (google::sparse_hash_set<int>::const_iterator it = sset.begin();
it != sset.end(); ++it)
printf("sset: %d\n", *it);
for (google::sparse_hash_map<int,int>::const_iterator it = smap.begin();
it != smap.end(); ++it)
printf("smap: %d -> %d\n", it->first, it->second);
for (google::dense_hash_set<int>::const_iterator it = dset.begin();
it != dset.end(); ++it)
printf("dset: %d\n", *it);
for (google::dense_hash_map<int,int>::const_iterator it = dmap.begin();
it != dmap.end(); ++it)
printf("dmap: %d -> %d\n", it->first, it->second);
}
for (int i = 0; i < 100; i++) {
CHECK_IFF(sset.find(i) != sset.end(), (i % 10) == 0);
CHECK_IFF(smap.find(i) != smap.end(), (i % 10) == 0);
CHECK_IFF(smap.find(i) != smap.end() && smap.find(i)->second == i+1,
(i % 10) == 0);
CHECK_IFF(dset.find(i) != dset.end(), (i % 10) == 5);
CHECK_IFF(dmap.find(i) != dmap.end(), (i % 10) == 5);
CHECK_IFF(dmap.find(i) != dmap.end() && dmap.find(i)->second == i+1,
(i % 10) == 5);
}
printf("PASS\n");
return 0;
}

View file

@ -0,0 +1,106 @@
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
//
// This tests mostly that we can #include the files correctly
// and have them work. This unittest purposefully does not
// #include <config.h>; it's meant to emulate what a 'regular
// install' of sparsehash would be able to see.
#include <sparsehash/internal/sparseconfig.h>
#include <config.h>
#include <stdio.h>
#include <sparsehash/sparse_hash_set>
#include <sparsehash/sparse_hash_map>
#include <sparsehash/dense_hash_set>
#include <sparsehash/dense_hash_map>
#include <sparsehash/template_util.h>
#include <sparsehash/type_traits.h>
#define CHECK_IFF(cond, when) do { \
if (when) { \
if (!(cond)) { \
puts("ERROR: " #cond " failed when " #when " is true\n"); \
exit(1); \
} \
} else { \
if (cond) { \
puts("ERROR: " #cond " succeeded when " #when " is false\n"); \
exit(1); \
} \
} \
} while (0)
int main(int argc, char**) {
// Run with an argument to get verbose output
const bool verbose = argc > 1;
google::sparse_hash_set<int> sset;
google::sparse_hash_map<int, int> smap;
google::dense_hash_set<int> dset;
google::dense_hash_map<int, int> dmap;
dset.set_empty_key(-1);
dmap.set_empty_key(-1);
for (int i = 0; i < 100; i += 10) { // go by tens
sset.insert(i);
smap[i] = i+1;
dset.insert(i + 5);
dmap[i+5] = i+6;
}
if (verbose) {
for (google::sparse_hash_set<int>::const_iterator it = sset.begin();
it != sset.end(); ++it)
printf("sset: %d\n", *it);
for (google::sparse_hash_map<int,int>::const_iterator it = smap.begin();
it != smap.end(); ++it)
printf("smap: %d -> %d\n", it->first, it->second);
for (google::dense_hash_set<int>::const_iterator it = dset.begin();
it != dset.end(); ++it)
printf("dset: %d\n", *it);
for (google::dense_hash_map<int,int>::const_iterator it = dmap.begin();
it != dmap.end(); ++it)
printf("dmap: %d -> %d\n", it->first, it->second);
}
for (int i = 0; i < 100; i++) {
CHECK_IFF(sset.find(i) != sset.end(), (i % 10) == 0);
CHECK_IFF(smap.find(i) != smap.end(), (i % 10) == 0);
CHECK_IFF(smap.find(i) != smap.end() && smap.find(i)->second == i+1,
(i % 10) == 0);
CHECK_IFF(dset.find(i) != dset.end(), (i % 10) == 5);
CHECK_IFF(dmap.find(i) != dmap.end(), (i % 10) == 5);
CHECK_IFF(dmap.find(i) != dmap.end() && dmap.find(i)->second == i+1,
(i % 10) == 5);
}
printf("PASS\n");
return 0;
}

View file

@ -0,0 +1,369 @@
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ----
//
// This is just a very thin wrapper over densehashtable.h, just
// like sgi stl's stl_hash_map is a very thin wrapper over
// stl_hashtable. The major thing we define is operator[], because
// we have a concept of a data_type which stl_hashtable doesn't
// (it only has a key and a value).
//
// NOTE: this is exactly like sparse_hash_map.h, with the word
// "sparse" replaced by "dense", except for the addition of
// set_empty_key().
//
// YOU MUST CALL SET_EMPTY_KEY() IMMEDIATELY AFTER CONSTRUCTION.
//
// Otherwise your program will die in mysterious ways. (Note if you
// use the constructor that takes an InputIterator range, you pass in
// the empty key in the constructor, rather than after. As a result,
// this constructor differs from the standard STL version.)
//
// In other respects, we adhere mostly to the STL semantics for
// hash-map. One important exception is that insert() may invalidate
// iterators entirely -- STL semantics are that insert() may reorder
// iterators, but they all still refer to something valid in the
// hashtable. Not so for us. Likewise, insert() may invalidate
// pointers into the hashtable. (Whether insert invalidates iterators
// and pointers depends on whether it results in a hashtable resize).
// On the plus side, delete() doesn't invalidate iterators or pointers
// at all, or even change the ordering of elements.
//
// Here are a few "power user" tips:
//
// 1) set_deleted_key():
// If you want to use erase() you *must* call set_deleted_key(),
// in addition to set_empty_key(), after construction.
// The deleted and empty keys must differ.
//
// 2) resize(0):
// When an item is deleted, its memory isn't freed right
// away. This allows you to iterate over a hashtable,
// and call erase(), without invalidating the iterator.
// To force the memory to be freed, call resize(0).
// For tr1 compatibility, this can also be called as rehash(0).
//
// 3) min_load_factor(0.0)
// Setting the minimum load factor to 0.0 guarantees that
// the hash table will never shrink.
//
// Roughly speaking:
// (1) dense_hash_map: fastest, uses the most memory unless entries are small
// (2) sparse_hash_map: slowest, uses the least memory
// (3) hash_map / unordered_map (STL): in the middle
//
// Typically I use sparse_hash_map when I care about space and/or when
// I need to save the hashtable on disk. I use hash_map otherwise. I
// don't personally use dense_hash_set ever; some people use it for
// small sets with lots of lookups.
//
// - dense_hash_map has, typically, about 78% memory overhead (if your
// data takes up X bytes, the hash_map uses .78X more bytes in overhead).
// - sparse_hash_map has about 4 bits overhead per entry.
// - sparse_hash_map can be 3-7 times slower than the others for lookup and,
// especially, inserts. See time_hash_map.cc for details.
//
// See /usr/(local/)?doc/sparsehash-*/dense_hash_map.html
// for information about how to use this class.
#ifndef _DENSE_HASH_MAP_H_
#define _DENSE_HASH_MAP_H_
#include <sparsehash/internal/sparseconfig.h>
#include <algorithm> // needed by stl_alloc
#include <functional> // for equal_to<>, select1st<>, etc
#include <memory> // for alloc
#include <utility> // for pair<>
#include <sparsehash/internal/densehashtable.h> // IWYU pragma: export
#include <sparsehash/internal/libc_allocator_with_realloc.h>
#include HASH_FUN_H // for hash<>
_START_GOOGLE_NAMESPACE_
template <class Key, class T,
class HashFcn = SPARSEHASH_HASH<Key>, // defined in sparseconfig.h
class EqualKey = std::equal_to<Key>,
class Alloc = libc_allocator_with_realloc<std::pair<const Key, T> > >
class dense_hash_map {
private:
// Apparently select1st is not stl-standard, so we define our own
struct SelectKey {
typedef const Key& result_type;
const Key& operator()(const std::pair<const Key, T>& p) const {
return p.first;
}
};
struct SetKey {
void operator()(std::pair<const Key, T>* value, const Key& new_key) const {
*const_cast<Key*>(&value->first) = new_key;
// It would be nice to clear the rest of value here as well, in
// case it's taking up a lot of memory. We do this by clearing
// the value. This assumes T has a zero-arg constructor!
value->second = T();
}
};
// For operator[].
struct DefaultValue {
std::pair<const Key, T> operator()(const Key& key) {
return std::make_pair(key, T());
}
};
// The actual data
typedef dense_hashtable<std::pair<const Key, T>, Key, HashFcn, SelectKey,
SetKey, EqualKey, Alloc> ht;
ht rep;
public:
typedef typename ht::key_type key_type;
typedef T data_type;
typedef T mapped_type;
typedef typename ht::value_type value_type;
typedef typename ht::hasher hasher;
typedef typename ht::key_equal key_equal;
typedef Alloc allocator_type;
typedef typename ht::size_type size_type;
typedef typename ht::difference_type difference_type;
typedef typename ht::pointer pointer;
typedef typename ht::const_pointer const_pointer;
typedef typename ht::reference reference;
typedef typename ht::const_reference const_reference;
typedef typename ht::iterator iterator;
typedef typename ht::const_iterator const_iterator;
typedef typename ht::local_iterator local_iterator;
typedef typename ht::const_local_iterator const_local_iterator;
// Iterator functions
iterator begin() { return rep.begin(); }
iterator end() { return rep.end(); }
const_iterator begin() const { return rep.begin(); }
const_iterator end() const { return rep.end(); }
// These come from tr1's unordered_map. For us, a bucket has 0 or 1 elements.
local_iterator begin(size_type i) { return rep.begin(i); }
local_iterator end(size_type i) { return rep.end(i); }
const_local_iterator begin(size_type i) const { return rep.begin(i); }
const_local_iterator end(size_type i) const { return rep.end(i); }
// Accessor functions
allocator_type get_allocator() const { return rep.get_allocator(); }
hasher hash_funct() const { return rep.hash_funct(); }
hasher hash_function() const { return hash_funct(); }
key_equal key_eq() const { return rep.key_eq(); }
// Constructors
explicit dense_hash_map(size_type expected_max_items_in_table = 0,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: rep(expected_max_items_in_table, hf, eql, SelectKey(), SetKey(), alloc) {
}
template <class InputIterator>
dense_hash_map(InputIterator f, InputIterator l,
const key_type& empty_key_val,
size_type expected_max_items_in_table = 0,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: rep(expected_max_items_in_table, hf, eql, SelectKey(), SetKey(), alloc) {
set_empty_key(empty_key_val);
rep.insert(f, l);
}
// We use the default copy constructor
// We use the default operator=()
// We use the default destructor
void clear() { rep.clear(); }
// This clears the hash map without resizing it down to the minimum
// bucket count, but rather keeps the number of buckets constant
void clear_no_resize() { rep.clear_no_resize(); }
void swap(dense_hash_map& hs) { rep.swap(hs.rep); }
// Functions concerning size
size_type size() const { return rep.size(); }
size_type max_size() const { return rep.max_size(); }
bool empty() const { return rep.empty(); }
size_type bucket_count() const { return rep.bucket_count(); }
size_type max_bucket_count() const { return rep.max_bucket_count(); }
// These are tr1 methods. bucket() is the bucket the key is or would be in.
size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
size_type bucket(const key_type& key) const { return rep.bucket(key); }
float load_factor() const {
return size() * 1.0f / bucket_count();
}
float max_load_factor() const {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
return grow;
}
void max_load_factor(float new_grow) {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
rep.set_resizing_parameters(shrink, new_grow);
}
// These aren't tr1 methods but perhaps ought to be.
float min_load_factor() const {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
return shrink;
}
void min_load_factor(float new_shrink) {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
rep.set_resizing_parameters(new_shrink, grow);
}
// Deprecated; use min_load_factor() or max_load_factor() instead.
void set_resizing_parameters(float shrink, float grow) {
rep.set_resizing_parameters(shrink, grow);
}
void resize(size_type hint) { rep.resize(hint); }
void rehash(size_type hint) { resize(hint); } // the tr1 name
// Lookup routines
iterator find(const key_type& key) { return rep.find(key); }
const_iterator find(const key_type& key) const { return rep.find(key); }
data_type& operator[](const key_type& key) { // This is our value-add!
// If key is in the hashtable, returns find(key)->second,
// otherwise returns insert(value_type(key, T()).first->second.
// Note it does not create an empty T unless the find fails.
return rep.template find_or_insert<DefaultValue>(key).second;
}
size_type count(const key_type& key) const { return rep.count(key); }
std::pair<iterator, iterator> equal_range(const key_type& key) {
return rep.equal_range(key);
}
std::pair<const_iterator, const_iterator> equal_range(const key_type& key)
const {
return rep.equal_range(key);
}
// Insertion routines
std::pair<iterator, bool> insert(const value_type& obj) {
return rep.insert(obj);
}
template <class InputIterator> void insert(InputIterator f, InputIterator l) {
rep.insert(f, l);
}
void insert(const_iterator f, const_iterator l) {
rep.insert(f, l);
}
// Required for std::insert_iterator; the passed-in iterator is ignored.
iterator insert(iterator, const value_type& obj) {
return insert(obj).first;
}
// Deletion and empty routines
// THESE ARE NON-STANDARD! I make you specify an "impossible" key
// value to identify deleted and empty buckets. You can change the
// deleted key as time goes on, or get rid of it entirely to be insert-only.
void set_empty_key(const key_type& key) { // YOU MUST CALL THIS!
rep.set_empty_key(value_type(key, data_type())); // rep wants a value
}
key_type empty_key() const {
return rep.empty_key().first; // rep returns a value
}
void set_deleted_key(const key_type& key) { rep.set_deleted_key(key); }
void clear_deleted_key() { rep.clear_deleted_key(); }
key_type deleted_key() const { return rep.deleted_key(); }
// These are standard
size_type erase(const key_type& key) { return rep.erase(key); }
void erase(iterator it) { rep.erase(it); }
void erase(iterator f, iterator l) { rep.erase(f, l); }
// Comparison
bool operator==(const dense_hash_map& hs) const { return rep == hs.rep; }
bool operator!=(const dense_hash_map& hs) const { return rep != hs.rep; }
// I/O -- this is an add-on for writing hash map to disk
//
// For maximum flexibility, this does not assume a particular
// file type (though it will probably be a FILE *). We just pass
// the fp through to rep.
// If your keys and values are simple enough, you can pass this
// serializer to serialize()/unserialize(). "Simple enough" means
// value_type is a POD type that contains no pointers. Note,
// however, we don't try to normalize endianness.
typedef typename ht::NopointerSerializer NopointerSerializer;
// serializer: a class providing operator()(OUTPUT*, const value_type&)
// (writing value_type to OUTPUT). You can specify a
// NopointerSerializer object if appropriate (see above).
// fp: either a FILE*, OR an ostream*/subclass_of_ostream*, OR a
// pointer to a class providing size_t Write(const void*, size_t),
// which writes a buffer into a stream (which fp presumably
// owns) and returns the number of bytes successfully written.
// Note basic_ostream<not_char> is not currently supported.
template <typename ValueSerializer, typename OUTPUT>
bool serialize(ValueSerializer serializer, OUTPUT* fp) {
return rep.serialize(serializer, fp);
}
// serializer: a functor providing operator()(INPUT*, value_type*)
// (reading from INPUT and into value_type). You can specify a
// NopointerSerializer object if appropriate (see above).
// fp: either a FILE*, OR an istream*/subclass_of_istream*, OR a
// pointer to a class providing size_t Read(void*, size_t),
// which reads into a buffer from a stream (which fp presumably
// owns) and returns the number of bytes successfully read.
// Note basic_istream<not_char> is not currently supported.
// NOTE: Since value_type is std::pair<const Key, T>, ValueSerializer
// may need to do a const cast in order to fill in the key.
template <typename ValueSerializer, typename INPUT>
bool unserialize(ValueSerializer serializer, INPUT* fp) {
return rep.unserialize(serializer, fp);
}
};
// We need a global swap as well
template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
inline void swap(dense_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm1,
dense_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm2) {
hm1.swap(hm2);
}
_END_GOOGLE_NAMESPACE_
#endif /* _DENSE_HASH_MAP_H_ */

View file

@ -0,0 +1,338 @@
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
//
// This is just a very thin wrapper over densehashtable.h, just
// like sgi stl's stl_hash_set is a very thin wrapper over
// stl_hashtable. The major thing we define is operator[], because
// we have a concept of a data_type which stl_hashtable doesn't
// (it only has a key and a value).
//
// This is more different from dense_hash_map than you might think,
// because all iterators for sets are const (you obviously can't
// change the key, and for sets there is no value).
//
// NOTE: this is exactly like sparse_hash_set.h, with the word
// "sparse" replaced by "dense", except for the addition of
// set_empty_key().
//
// YOU MUST CALL SET_EMPTY_KEY() IMMEDIATELY AFTER CONSTRUCTION.
//
// Otherwise your program will die in mysterious ways. (Note if you
// use the constructor that takes an InputIterator range, you pass in
// the empty key in the constructor, rather than after. As a result,
// this constructor differs from the standard STL version.)
//
// In other respects, we adhere mostly to the STL semantics for
// hash-map. One important exception is that insert() may invalidate
// iterators entirely -- STL semantics are that insert() may reorder
// iterators, but they all still refer to something valid in the
// hashtable. Not so for us. Likewise, insert() may invalidate
// pointers into the hashtable. (Whether insert invalidates iterators
// and pointers depends on whether it results in a hashtable resize).
// On the plus side, delete() doesn't invalidate iterators or pointers
// at all, or even change the ordering of elements.
//
// Here are a few "power user" tips:
//
// 1) set_deleted_key():
// If you want to use erase() you must call set_deleted_key(),
// in addition to set_empty_key(), after construction.
// The deleted and empty keys must differ.
//
// 2) resize(0):
// When an item is deleted, its memory isn't freed right
// away. This allows you to iterate over a hashtable,
// and call erase(), without invalidating the iterator.
// To force the memory to be freed, call resize(0).
// For tr1 compatibility, this can also be called as rehash(0).
//
// 3) min_load_factor(0.0)
// Setting the minimum load factor to 0.0 guarantees that
// the hash table will never shrink.
//
// Roughly speaking:
// (1) dense_hash_set: fastest, uses the most memory unless entries are small
// (2) sparse_hash_set: slowest, uses the least memory
// (3) hash_set / unordered_set (STL): in the middle
//
// Typically I use sparse_hash_set when I care about space and/or when
// I need to save the hashtable on disk. I use hash_set otherwise. I
// don't personally use dense_hash_set ever; some people use it for
// small sets with lots of lookups.
//
// - dense_hash_set has, typically, about 78% memory overhead (if your
// data takes up X bytes, the hash_set uses .78X more bytes in overhead).
// - sparse_hash_set has about 4 bits overhead per entry.
// - sparse_hash_set can be 3-7 times slower than the others for lookup and,
// especially, inserts. See time_hash_map.cc for details.
//
// See /usr/(local/)?doc/sparsehash-*/dense_hash_set.html
// for information about how to use this class.
#ifndef _DENSE_HASH_SET_H_
#define _DENSE_HASH_SET_H_
#include <sparsehash/internal/sparseconfig.h>
#include <algorithm> // needed by stl_alloc
#include <functional> // for equal_to<>, select1st<>, etc
#include <memory> // for alloc
#include <utility> // for pair<>
#include <sparsehash/internal/densehashtable.h> // IWYU pragma: export
#include <sparsehash/internal/libc_allocator_with_realloc.h>
#include HASH_FUN_H // for hash<>
_START_GOOGLE_NAMESPACE_
template <class Value,
class HashFcn = SPARSEHASH_HASH<Value>, // defined in sparseconfig.h
class EqualKey = std::equal_to<Value>,
class Alloc = libc_allocator_with_realloc<Value> >
class dense_hash_set {
private:
// Apparently identity is not stl-standard, so we define our own
struct Identity {
typedef const Value& result_type;
const Value& operator()(const Value& v) const { return v; }
};
struct SetKey {
void operator()(Value* value, const Value& new_key) const {
*value = new_key;
}
};
// The actual data
typedef dense_hashtable<Value, Value, HashFcn, Identity, SetKey,
EqualKey, Alloc> ht;
ht rep;
public:
typedef typename ht::key_type key_type;
typedef typename ht::value_type value_type;
typedef typename ht::hasher hasher;
typedef typename ht::key_equal key_equal;
typedef Alloc allocator_type;
typedef typename ht::size_type size_type;
typedef typename ht::difference_type difference_type;
typedef typename ht::const_pointer pointer;
typedef typename ht::const_pointer const_pointer;
typedef typename ht::const_reference reference;
typedef typename ht::const_reference const_reference;
typedef typename ht::const_iterator iterator;
typedef typename ht::const_iterator const_iterator;
typedef typename ht::const_local_iterator local_iterator;
typedef typename ht::const_local_iterator const_local_iterator;
// Iterator functions -- recall all iterators are const
iterator begin() const { return rep.begin(); }
iterator end() const { return rep.end(); }
// These come from tr1's unordered_set. For us, a bucket has 0 or 1 elements.
local_iterator begin(size_type i) const { return rep.begin(i); }
local_iterator end(size_type i) const { return rep.end(i); }
// Accessor functions
allocator_type get_allocator() const { return rep.get_allocator(); }
hasher hash_funct() const { return rep.hash_funct(); }
hasher hash_function() const { return hash_funct(); } // tr1 name
key_equal key_eq() const { return rep.key_eq(); }
// Constructors
explicit dense_hash_set(size_type expected_max_items_in_table = 0,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
}
template <class InputIterator>
dense_hash_set(InputIterator f, InputIterator l,
const key_type& empty_key_val,
size_type expected_max_items_in_table = 0,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
set_empty_key(empty_key_val);
rep.insert(f, l);
}
// We use the default copy constructor
// We use the default operator=()
// We use the default destructor
void clear() { rep.clear(); }
// This clears the hash set without resizing it down to the minimum
// bucket count, but rather keeps the number of buckets constant
void clear_no_resize() { rep.clear_no_resize(); }
void swap(dense_hash_set& hs) { rep.swap(hs.rep); }
// Functions concerning size
size_type size() const { return rep.size(); }
size_type max_size() const { return rep.max_size(); }
bool empty() const { return rep.empty(); }
size_type bucket_count() const { return rep.bucket_count(); }
size_type max_bucket_count() const { return rep.max_bucket_count(); }
// These are tr1 methods. bucket() is the bucket the key is or would be in.
size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
size_type bucket(const key_type& key) const { return rep.bucket(key); }
float load_factor() const {
return size() * 1.0f / bucket_count();
}
float max_load_factor() const {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
return grow;
}
void max_load_factor(float new_grow) {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
rep.set_resizing_parameters(shrink, new_grow);
}
// These aren't tr1 methods but perhaps ought to be.
float min_load_factor() const {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
return shrink;
}
void min_load_factor(float new_shrink) {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
rep.set_resizing_parameters(new_shrink, grow);
}
// Deprecated; use min_load_factor() or max_load_factor() instead.
void set_resizing_parameters(float shrink, float grow) {
rep.set_resizing_parameters(shrink, grow);
}
void resize(size_type hint) { rep.resize(hint); }
void rehash(size_type hint) { resize(hint); } // the tr1 name
// Lookup routines
iterator find(const key_type& key) const { return rep.find(key); }
size_type count(const key_type& key) const { return rep.count(key); }
std::pair<iterator, iterator> equal_range(const key_type& key) const {
return rep.equal_range(key);
}
// Insertion routines
std::pair<iterator, bool> insert(const value_type& obj) {
std::pair<typename ht::iterator, bool> p = rep.insert(obj);
return std::pair<iterator, bool>(p.first, p.second); // const to non-const
}
template <class InputIterator> void insert(InputIterator f, InputIterator l) {
rep.insert(f, l);
}
void insert(const_iterator f, const_iterator l) {
rep.insert(f, l);
}
// Required for std::insert_iterator; the passed-in iterator is ignored.
iterator insert(iterator, const value_type& obj) {
return insert(obj).first;
}
// Deletion and empty routines
// THESE ARE NON-STANDARD! I make you specify an "impossible" key
// value to identify deleted and empty buckets. You can change the
// deleted key as time goes on, or get rid of it entirely to be insert-only.
void set_empty_key(const key_type& key) { rep.set_empty_key(key); }
key_type empty_key() const { return rep.empty_key(); }
void set_deleted_key(const key_type& key) { rep.set_deleted_key(key); }
void clear_deleted_key() { rep.clear_deleted_key(); }
key_type deleted_key() const { return rep.deleted_key(); }
// These are standard
size_type erase(const key_type& key) { return rep.erase(key); }
void erase(iterator it) { rep.erase(it); }
void erase(iterator f, iterator l) { rep.erase(f, l); }
// Comparison
bool operator==(const dense_hash_set& hs) const { return rep == hs.rep; }
bool operator!=(const dense_hash_set& hs) const { return rep != hs.rep; }
// I/O -- this is an add-on for writing metainformation to disk
//
// For maximum flexibility, this does not assume a particular
// file type (though it will probably be a FILE *). We just pass
// the fp through to rep.
// If your keys and values are simple enough, you can pass this
// serializer to serialize()/unserialize(). "Simple enough" means
// value_type is a POD type that contains no pointers. Note,
// however, we don't try to normalize endianness.
typedef typename ht::NopointerSerializer NopointerSerializer;
// serializer: a class providing operator()(OUTPUT*, const value_type&)
// (writing value_type to OUTPUT). You can specify a
// NopointerSerializer object if appropriate (see above).
// fp: either a FILE*, OR an ostream*/subclass_of_ostream*, OR a
// pointer to a class providing size_t Write(const void*, size_t),
// which writes a buffer into a stream (which fp presumably
// owns) and returns the number of bytes successfully written.
// Note basic_ostream<not_char> is not currently supported.
template <typename ValueSerializer, typename OUTPUT>
bool serialize(ValueSerializer serializer, OUTPUT* fp) {
return rep.serialize(serializer, fp);
}
// serializer: a functor providing operator()(INPUT*, value_type*)
// (reading from INPUT and into value_type). You can specify a
// NopointerSerializer object if appropriate (see above).
// fp: either a FILE*, OR an istream*/subclass_of_istream*, OR a
// pointer to a class providing size_t Read(void*, size_t),
// which reads into a buffer from a stream (which fp presumably
// owns) and returns the number of bytes successfully read.
// Note basic_istream<not_char> is not currently supported.
template <typename ValueSerializer, typename INPUT>
bool unserialize(ValueSerializer serializer, INPUT* fp) {
return rep.unserialize(serializer, fp);
}
};
template <class Val, class HashFcn, class EqualKey, class Alloc>
inline void swap(dense_hash_set<Val, HashFcn, EqualKey, Alloc>& hs1,
dense_hash_set<Val, HashFcn, EqualKey, Alloc>& hs2) {
hs1.swap(hs2);
}
_END_GOOGLE_NAMESPACE_
#endif /* _DENSE_HASH_SET_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,381 @@
// Copyright (c) 2010, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
//
// Provides classes shared by both sparse and dense hashtable.
//
// sh_hashtable_settings has parameters for growing and shrinking
// a hashtable. It also packages zero-size functor (ie. hasher).
//
// Other functions and classes provide common code for serializing
// and deserializing hashtables to a stream (such as a FILE*).
#ifndef UTIL_GTL_HASHTABLE_COMMON_H_
#define UTIL_GTL_HASHTABLE_COMMON_H_
#include <sparsehash/internal/sparseconfig.h>
#include <assert.h>
#include <stdio.h>
#include <stddef.h> // for size_t
#include <iosfwd>
#include <stdexcept> // For length_error
_START_GOOGLE_NAMESPACE_
template <bool> struct SparsehashCompileAssert { };
#define SPARSEHASH_COMPILE_ASSERT(expr, msg) \
__attribute__((unused)) typedef SparsehashCompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
namespace sparsehash_internal {
// Adaptor methods for reading/writing data from an INPUT or OUPTUT
// variable passed to serialize() or unserialize(). For now we
// have implemented INPUT/OUTPUT for FILE*, istream*/ostream* (note
// they are pointers, unlike typical use), or else a pointer to
// something that supports a Read()/Write() method.
//
// For technical reasons, we implement read_data/write_data in two
// stages. The actual work is done in *_data_internal, which takes
// the stream argument twice: once as a template type, and once with
// normal type information. (We only use the second version.) We do
// this because of how C++ picks what function overload to use. If we
// implemented this the naive way:
// bool read_data(istream* is, const void* data, size_t length);
// template<typename T> read_data(T* fp, const void* data, size_t length);
// C++ would prefer the second version for every stream type except
// istream. However, we want C++ to prefer the first version for
// streams that are *subclasses* of istream, such as istringstream.
// This is not possible given the way template types are resolved. So
// we split the stream argument in two, one of which is templated and
// one of which is not. The specialized functions (like the istream
// version above) ignore the template arg and use the second, 'type'
// arg, getting subclass matching as normal. The 'catch-all'
// functions (the second version above) use the template arg to deduce
// the type, and use a second, void* arg to achieve the desired
// 'catch-all' semantics.
// ----- low-level I/O for FILE* ----
template<typename Ignored>
inline bool read_data_internal(Ignored*, FILE* fp,
void* data, size_t length) {
return fread(data, length, 1, fp) == 1;
}
template<typename Ignored>
inline bool write_data_internal(Ignored*, FILE* fp,
const void* data, size_t length) {
return fwrite(data, length, 1, fp) == 1;
}
// ----- low-level I/O for iostream ----
// We want the caller to be responsible for #including <iostream>, not
// us, because iostream is a big header! According to the standard,
// it's only legal to delay the instantiation the way we want to if
// the istream/ostream is a template type. So we jump through hoops.
template<typename ISTREAM>
inline bool read_data_internal_for_istream(ISTREAM* fp,
void* data, size_t length) {
return fp->read(reinterpret_cast<char*>(data), length).good();
}
template<typename Ignored>
inline bool read_data_internal(Ignored*, std::istream* fp,
void* data, size_t length) {
return read_data_internal_for_istream(fp, data, length);
}
template<typename OSTREAM>
inline bool write_data_internal_for_ostream(OSTREAM* fp,
const void* data, size_t length) {
return fp->write(reinterpret_cast<const char*>(data), length).good();
}
template<typename Ignored>
inline bool write_data_internal(Ignored*, std::ostream* fp,
const void* data, size_t length) {
return write_data_internal_for_ostream(fp, data, length);
}
// ----- low-level I/O for custom streams ----
// The INPUT type needs to support a Read() method that takes a
// buffer and a length and returns the number of bytes read.
template <typename INPUT>
inline bool read_data_internal(INPUT* fp, void*,
void* data, size_t length) {
return static_cast<size_t>(fp->Read(data, length)) == length;
}
// The OUTPUT type needs to support a Write() operation that takes
// a buffer and a length and returns the number of bytes written.
template <typename OUTPUT>
inline bool write_data_internal(OUTPUT* fp, void*,
const void* data, size_t length) {
return static_cast<size_t>(fp->Write(data, length)) == length;
}
// ----- low-level I/O: the public API ----
template <typename INPUT>
inline bool read_data(INPUT* fp, void* data, size_t length) {
return read_data_internal(fp, fp, data, length);
}
template <typename OUTPUT>
inline bool write_data(OUTPUT* fp, const void* data, size_t length) {
return write_data_internal(fp, fp, data, length);
}
// Uses read_data() and write_data() to read/write an integer.
// length is the number of bytes to read/write (which may differ
// from sizeof(IntType), allowing us to save on a 32-bit system
// and load on a 64-bit system). Excess bytes are taken to be 0.
// INPUT and OUTPUT must match legal inputs to read/write_data (above).
template <typename INPUT, typename IntType>
bool read_bigendian_number(INPUT* fp, IntType* value, size_t length) {
*value = 0;
unsigned char byte;
// We require IntType to be unsigned or else the shifting gets all screwy.
SPARSEHASH_COMPILE_ASSERT(static_cast<IntType>(-1) > static_cast<IntType>(0),
serializing_int_requires_an_unsigned_type);
for (size_t i = 0; i < length; ++i) {
if (!read_data(fp, &byte, sizeof(byte))) return false;
*value |= static_cast<IntType>(byte) << ((length - 1 - i) * 8);
}
return true;
}
template <typename OUTPUT, typename IntType>
bool write_bigendian_number(OUTPUT* fp, IntType value, size_t length) {
unsigned char byte;
// We require IntType to be unsigned or else the shifting gets all screwy.
SPARSEHASH_COMPILE_ASSERT(static_cast<IntType>(-1) > static_cast<IntType>(0),
serializing_int_requires_an_unsigned_type);
for (size_t i = 0; i < length; ++i) {
byte = (sizeof(value) <= length-1 - i)
? 0 : static_cast<unsigned char>((value >> ((length-1 - i) * 8)) & 255);
if (!write_data(fp, &byte, sizeof(byte))) return false;
}
return true;
}
// If your keys and values are simple enough, you can pass this
// serializer to serialize()/unserialize(). "Simple enough" means
// value_type is a POD type that contains no pointers. Note,
// however, we don't try to normalize endianness.
// This is the type used for NopointerSerializer.
template <typename value_type> struct pod_serializer {
template <typename INPUT>
bool operator()(INPUT* fp, value_type* value) const {
return read_data(fp, value, sizeof(*value));
}
template <typename OUTPUT>
bool operator()(OUTPUT* fp, const value_type& value) const {
return write_data(fp, &value, sizeof(value));
}
};
// Settings contains parameters for growing and shrinking the table.
// It also packages zero-size functor (ie. hasher).
//
// It does some munging of the hash value in cases where we think
// (fear) the original hash function might not be very good. In
// particular, the default hash of pointers is the identity hash,
// so probably all the low bits are 0. We identify when we think
// we're hashing a pointer, and chop off the low bits. Note this
// isn't perfect: even when the key is a pointer, we can't tell
// for sure that the hash is the identity hash. If it's not, this
// is needless work (and possibly, though not likely, harmful).
template<typename Key, typename HashFunc,
typename SizeType, int HT_MIN_BUCKETS>
class sh_hashtable_settings : public HashFunc {
public:
typedef Key key_type;
typedef HashFunc hasher;
typedef SizeType size_type;
public:
sh_hashtable_settings(const hasher& hf,
const float ht_occupancy_flt,
const float ht_empty_flt)
: hasher(hf),
enlarge_threshold_(0),
shrink_threshold_(0),
consider_shrink_(false),
use_empty_(false),
use_deleted_(false),
num_ht_copies_(0) {
set_enlarge_factor(ht_occupancy_flt);
set_shrink_factor(ht_empty_flt);
}
size_type hash(const key_type& v) const {
// We munge the hash value when we don't trust hasher::operator().
return hash_munger<Key>::MungedHash(hasher::operator()(v));
}
float enlarge_factor() const {
return enlarge_factor_;
}
void set_enlarge_factor(float f) {
enlarge_factor_ = f;
}
float shrink_factor() const {
return shrink_factor_;
}
void set_shrink_factor(float f) {
shrink_factor_ = f;
}
size_type enlarge_threshold() const {
return enlarge_threshold_;
}
void set_enlarge_threshold(size_type t) {
enlarge_threshold_ = t;
}
size_type shrink_threshold() const {
return shrink_threshold_;
}
void set_shrink_threshold(size_type t) {
shrink_threshold_ = t;
}
size_type enlarge_size(size_type x) const {
return static_cast<size_type>(x * enlarge_factor_);
}
size_type shrink_size(size_type x) const {
return static_cast<size_type>(x * shrink_factor_);
}
bool consider_shrink() const {
return consider_shrink_;
}
void set_consider_shrink(bool t) {
consider_shrink_ = t;
}
bool use_empty() const {
return use_empty_;
}
void set_use_empty(bool t) {
use_empty_ = t;
}
bool use_deleted() const {
return use_deleted_;
}
void set_use_deleted(bool t) {
use_deleted_ = t;
}
size_type num_ht_copies() const {
return static_cast<size_type>(num_ht_copies_);
}
void inc_num_ht_copies() {
++num_ht_copies_;
}
// Reset the enlarge and shrink thresholds
void reset_thresholds(size_type num_buckets) {
set_enlarge_threshold(enlarge_size(num_buckets));
set_shrink_threshold(shrink_size(num_buckets));
// whatever caused us to reset already considered
set_consider_shrink(false);
}
// Caller is resposible for calling reset_threshold right after
// set_resizing_parameters.
void set_resizing_parameters(float shrink, float grow) {
assert(shrink >= 0.0);
assert(grow <= 1.0);
if (shrink > grow/2.0f)
shrink = grow / 2.0f; // otherwise we thrash hashtable size
set_shrink_factor(shrink);
set_enlarge_factor(grow);
}
// This is the smallest size a hashtable can be without being too crowded
// If you like, you can give a min #buckets as well as a min #elts
size_type min_buckets(size_type num_elts, size_type min_buckets_wanted) {
float enlarge = enlarge_factor();
size_type sz = HT_MIN_BUCKETS; // min buckets allowed
while ( sz < min_buckets_wanted ||
num_elts >= static_cast<size_type>(sz * enlarge) ) {
// This just prevents overflowing size_type, since sz can exceed
// max_size() here.
if (static_cast<size_type>(sz * 2) < sz) {
throw std::length_error("resize overflow"); // protect against overflow
}
sz *= 2;
}
return sz;
}
private:
template<class HashKey> class hash_munger {
public:
static size_t MungedHash(size_t hash) {
return hash;
}
};
// This matches when the hashtable key is a pointer.
template<class HashKey> class hash_munger<HashKey*> {
public:
static size_t MungedHash(size_t hash) {
// TODO(csilvers): consider rotating instead:
// static const int shift = (sizeof(void *) == 4) ? 2 : 3;
// return (hash << (sizeof(hash) * 8) - shift)) | (hash >> shift);
// This matters if we ever change sparse/dense_hash_* to compare
// hashes before comparing actual values. It's speedy on x86.
return hash / sizeof(void*); // get rid of known-0 bits
}
};
size_type enlarge_threshold_; // table.size() * enlarge_factor
size_type shrink_threshold_; // table.size() * shrink_factor
float enlarge_factor_; // how full before resize
float shrink_factor_; // how empty before resize
// consider_shrink=true if we should try to shrink before next insert
bool consider_shrink_;
bool use_empty_; // used only by densehashtable, not sparsehashtable
bool use_deleted_; // false until delkey has been set
// num_ht_copies is a counter incremented every Copy/Move
unsigned int num_ht_copies_;
};
} // namespace sparsehash_internal
#undef SPARSEHASH_COMPILE_ASSERT
_END_GOOGLE_NAMESPACE_
#endif // UTIL_GTL_HASHTABLE_COMMON_H_

View file

@ -0,0 +1,119 @@
// Copyright (c) 2010, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
#ifndef UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_
#define UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_
#include <sparsehash/internal/sparseconfig.h>
#include <stdlib.h> // for malloc/realloc/free
#include <stddef.h> // for ptrdiff_t
#include <new> // for placement new
_START_GOOGLE_NAMESPACE_
template<class T>
class libc_allocator_with_realloc {
public:
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
libc_allocator_with_realloc() {}
libc_allocator_with_realloc(const libc_allocator_with_realloc&) {}
~libc_allocator_with_realloc() {}
pointer address(reference r) const { return &r; }
const_pointer address(const_reference r) const { return &r; }
pointer allocate(size_type n, const_pointer = 0) {
return static_cast<pointer>(malloc(n * sizeof(value_type)));
}
void deallocate(pointer p, size_type) {
free(p);
}
pointer reallocate(pointer p, size_type n) {
return static_cast<pointer>(realloc(p, n * sizeof(value_type)));
}
size_type max_size() const {
return static_cast<size_type>(-1) / sizeof(value_type);
}
void construct(pointer p, const value_type& val) {
new(p) value_type(val);
}
void destroy(pointer p) { p->~value_type(); }
template <class U>
libc_allocator_with_realloc(const libc_allocator_with_realloc<U>&) {}
template<class U>
struct rebind {
typedef libc_allocator_with_realloc<U> other;
};
};
// libc_allocator_with_realloc<void> specialization.
template<>
class libc_allocator_with_realloc<void> {
public:
typedef void value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef void* pointer;
typedef const void* const_pointer;
template<class U>
struct rebind {
typedef libc_allocator_with_realloc<U> other;
};
};
template<class T>
inline bool operator==(const libc_allocator_with_realloc<T>&,
const libc_allocator_with_realloc<T>&) {
return true;
}
template<class T>
inline bool operator!=(const libc_allocator_with_realloc<T>&,
const libc_allocator_with_realloc<T>&) {
return false;
}
_END_GOOGLE_NAMESPACE_
#endif // UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,363 @@
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
//
// This is just a very thin wrapper over sparsehashtable.h, just
// like sgi stl's stl_hash_map is a very thin wrapper over
// stl_hashtable. The major thing we define is operator[], because
// we have a concept of a data_type which stl_hashtable doesn't
// (it only has a key and a value).
//
// We adhere mostly to the STL semantics for hash-map. One important
// exception is that insert() may invalidate iterators entirely -- STL
// semantics are that insert() may reorder iterators, but they all
// still refer to something valid in the hashtable. Not so for us.
// Likewise, insert() may invalidate pointers into the hashtable.
// (Whether insert invalidates iterators and pointers depends on
// whether it results in a hashtable resize). On the plus side,
// delete() doesn't invalidate iterators or pointers at all, or even
// change the ordering of elements.
//
// Here are a few "power user" tips:
//
// 1) set_deleted_key():
// Unlike STL's hash_map, if you want to use erase() you
// *must* call set_deleted_key() after construction.
//
// 2) resize(0):
// When an item is deleted, its memory isn't freed right
// away. This is what allows you to iterate over a hashtable
// and call erase() without invalidating the iterator.
// To force the memory to be freed, call resize(0).
// For tr1 compatibility, this can also be called as rehash(0).
//
// 3) min_load_factor(0.0)
// Setting the minimum load factor to 0.0 guarantees that
// the hash table will never shrink.
//
// Roughly speaking:
// (1) dense_hash_map: fastest, uses the most memory unless entries are small
// (2) sparse_hash_map: slowest, uses the least memory
// (3) hash_map / unordered_map (STL): in the middle
//
// Typically I use sparse_hash_map when I care about space and/or when
// I need to save the hashtable on disk. I use hash_map otherwise. I
// don't personally use dense_hash_map ever; some people use it for
// small maps with lots of lookups.
//
// - dense_hash_map has, typically, about 78% memory overhead (if your
// data takes up X bytes, the hash_map uses .78X more bytes in overhead).
// - sparse_hash_map has about 4 bits overhead per entry.
// - sparse_hash_map can be 3-7 times slower than the others for lookup and,
// especially, inserts. See time_hash_map.cc for details.
//
// See /usr/(local/)?doc/sparsehash-*/sparse_hash_map.html
// for information about how to use this class.
#ifndef _SPARSE_HASH_MAP_H_
#define _SPARSE_HASH_MAP_H_
#include <sparsehash/internal/sparseconfig.h>
#include <algorithm> // needed by stl_alloc
#include <functional> // for equal_to<>, select1st<>, etc
#include <memory> // for alloc
#include <utility> // for pair<>
#include <sparsehash/internal/libc_allocator_with_realloc.h>
#include <sparsehash/internal/sparsehashtable.h> // IWYU pragma: export
#include HASH_FUN_H // for hash<>
_START_GOOGLE_NAMESPACE_
template <class Key, class T,
class HashFcn = SPARSEHASH_HASH<Key>, // defined in sparseconfig.h
class EqualKey = std::equal_to<Key>,
class Alloc = libc_allocator_with_realloc<std::pair<const Key, T> > >
class sparse_hash_map {
private:
// Apparently select1st is not stl-standard, so we define our own
struct SelectKey {
typedef const Key& result_type;
const Key& operator()(const std::pair<const Key, T>& p) const {
return p.first;
}
};
struct SetKey {
void operator()(std::pair<const Key, T>* value, const Key& new_key) const {
*const_cast<Key*>(&value->first) = new_key;
// It would be nice to clear the rest of value here as well, in
// case it's taking up a lot of memory. We do this by clearing
// the value. This assumes T has a zero-arg constructor!
value->second = T();
}
};
// For operator[].
struct DefaultValue {
std::pair<const Key, T> operator()(const Key& key) {
return std::make_pair(key, T());
}
};
// The actual data
typedef sparse_hashtable<std::pair<const Key, T>, Key, HashFcn, SelectKey,
SetKey, EqualKey, Alloc> ht;
ht rep;
public:
typedef typename ht::key_type key_type;
typedef T data_type;
typedef T mapped_type;
typedef typename ht::value_type value_type;
typedef typename ht::hasher hasher;
typedef typename ht::key_equal key_equal;
typedef Alloc allocator_type;
typedef typename ht::size_type size_type;
typedef typename ht::difference_type difference_type;
typedef typename ht::pointer pointer;
typedef typename ht::const_pointer const_pointer;
typedef typename ht::reference reference;
typedef typename ht::const_reference const_reference;
typedef typename ht::iterator iterator;
typedef typename ht::const_iterator const_iterator;
typedef typename ht::local_iterator local_iterator;
typedef typename ht::const_local_iterator const_local_iterator;
// Iterator functions
iterator begin() { return rep.begin(); }
iterator end() { return rep.end(); }
const_iterator begin() const { return rep.begin(); }
const_iterator end() const { return rep.end(); }
// These come from tr1's unordered_map. For us, a bucket has 0 or 1 elements.
local_iterator begin(size_type i) { return rep.begin(i); }
local_iterator end(size_type i) { return rep.end(i); }
const_local_iterator begin(size_type i) const { return rep.begin(i); }
const_local_iterator end(size_type i) const { return rep.end(i); }
// Accessor functions
allocator_type get_allocator() const { return rep.get_allocator(); }
hasher hash_funct() const { return rep.hash_funct(); }
hasher hash_function() const { return hash_funct(); }
key_equal key_eq() const { return rep.key_eq(); }
// Constructors
explicit sparse_hash_map(size_type expected_max_items_in_table = 0,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: rep(expected_max_items_in_table, hf, eql, SelectKey(), SetKey(), alloc) {
}
template <class InputIterator>
sparse_hash_map(InputIterator f, InputIterator l,
size_type expected_max_items_in_table = 0,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: rep(expected_max_items_in_table, hf, eql, SelectKey(), SetKey(), alloc) {
rep.insert(f, l);
}
// We use the default copy constructor
// We use the default operator=()
// We use the default destructor
void clear() { rep.clear(); }
void swap(sparse_hash_map& hs) { rep.swap(hs.rep); }
// Functions concerning size
size_type size() const { return rep.size(); }
size_type max_size() const { return rep.max_size(); }
bool empty() const { return rep.empty(); }
size_type bucket_count() const { return rep.bucket_count(); }
size_type max_bucket_count() const { return rep.max_bucket_count(); }
// These are tr1 methods. bucket() is the bucket the key is or would be in.
size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
size_type bucket(const key_type& key) const { return rep.bucket(key); }
float load_factor() const {
return size() * 1.0f / bucket_count();
}
float max_load_factor() const {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
return grow;
}
void max_load_factor(float new_grow) {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
rep.set_resizing_parameters(shrink, new_grow);
}
// These aren't tr1 methods but perhaps ought to be.
float min_load_factor() const {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
return shrink;
}
void min_load_factor(float new_shrink) {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
rep.set_resizing_parameters(new_shrink, grow);
}
// Deprecated; use min_load_factor() or max_load_factor() instead.
void set_resizing_parameters(float shrink, float grow) {
rep.set_resizing_parameters(shrink, grow);
}
void resize(size_type hint) { rep.resize(hint); }
void rehash(size_type hint) { resize(hint); } // the tr1 name
// Lookup routines
iterator find(const key_type& key) { return rep.find(key); }
const_iterator find(const key_type& key) const { return rep.find(key); }
data_type& operator[](const key_type& key) { // This is our value-add!
// If key is in the hashtable, returns find(key)->second,
// otherwise returns insert(value_type(key, T()).first->second.
// Note it does not create an empty T unless the find fails.
return rep.template find_or_insert<DefaultValue>(key).second;
}
size_type count(const key_type& key) const { return rep.count(key); }
std::pair<iterator, iterator> equal_range(const key_type& key) {
return rep.equal_range(key);
}
std::pair<const_iterator, const_iterator> equal_range(const key_type& key)
const {
return rep.equal_range(key);
}
// Insertion routines
std::pair<iterator, bool> insert(const value_type& obj) {
return rep.insert(obj);
}
template <class InputIterator> void insert(InputIterator f, InputIterator l) {
rep.insert(f, l);
}
void insert(const_iterator f, const_iterator l) {
rep.insert(f, l);
}
// Required for std::insert_iterator; the passed-in iterator is ignored.
iterator insert(iterator, const value_type& obj) {
return insert(obj).first;
}
// Deletion routines
// THESE ARE NON-STANDARD! I make you specify an "impossible" key
// value to identify deleted buckets. You can change the key as
// time goes on, or get rid of it entirely to be insert-only.
void set_deleted_key(const key_type& key) {
rep.set_deleted_key(key);
}
void clear_deleted_key() { rep.clear_deleted_key(); }
key_type deleted_key() const { return rep.deleted_key(); }
// These are standard
size_type erase(const key_type& key) { return rep.erase(key); }
void erase(iterator it) { rep.erase(it); }
void erase(iterator f, iterator l) { rep.erase(f, l); }
// Comparison
bool operator==(const sparse_hash_map& hs) const { return rep == hs.rep; }
bool operator!=(const sparse_hash_map& hs) const { return rep != hs.rep; }
// I/O -- this is an add-on for writing metainformation to disk
//
// For maximum flexibility, this does not assume a particular
// file type (though it will probably be a FILE *). We just pass
// the fp through to rep.
// If your keys and values are simple enough, you can pass this
// serializer to serialize()/unserialize(). "Simple enough" means
// value_type is a POD type that contains no pointers. Note,
// however, we don't try to normalize endianness.
typedef typename ht::NopointerSerializer NopointerSerializer;
// serializer: a class providing operator()(OUTPUT*, const value_type&)
// (writing value_type to OUTPUT). You can specify a
// NopointerSerializer object if appropriate (see above).
// fp: either a FILE*, OR an ostream*/subclass_of_ostream*, OR a
// pointer to a class providing size_t Write(const void*, size_t),
// which writes a buffer into a stream (which fp presumably
// owns) and returns the number of bytes successfully written.
// Note basic_ostream<not_char> is not currently supported.
template <typename ValueSerializer, typename OUTPUT>
bool serialize(ValueSerializer serializer, OUTPUT* fp) {
return rep.serialize(serializer, fp);
}
// serializer: a functor providing operator()(INPUT*, value_type*)
// (reading from INPUT and into value_type). You can specify a
// NopointerSerializer object if appropriate (see above).
// fp: either a FILE*, OR an istream*/subclass_of_istream*, OR a
// pointer to a class providing size_t Read(void*, size_t),
// which reads into a buffer from a stream (which fp presumably
// owns) and returns the number of bytes successfully read.
// Note basic_istream<not_char> is not currently supported.
// NOTE: Since value_type is std::pair<const Key, T>, ValueSerializer
// may need to do a const cast in order to fill in the key.
// NOTE: if Key or T are not POD types, the serializer MUST use
// placement-new to initialize their values, rather than a normal
// equals-assignment or similar. (The value_type* passed into the
// serializer points to garbage memory.)
template <typename ValueSerializer, typename INPUT>
bool unserialize(ValueSerializer serializer, INPUT* fp) {
return rep.unserialize(serializer, fp);
}
// The four methods below are DEPRECATED.
// Use serialize() and unserialize() for new code.
template <typename OUTPUT>
bool write_metadata(OUTPUT *fp) { return rep.write_metadata(fp); }
template <typename INPUT>
bool read_metadata(INPUT *fp) { return rep.read_metadata(fp); }
template <typename OUTPUT>
bool write_nopointer_data(OUTPUT *fp) { return rep.write_nopointer_data(fp); }
template <typename INPUT>
bool read_nopointer_data(INPUT *fp) { return rep.read_nopointer_data(fp); }
};
// We need a global swap as well
template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
inline void swap(sparse_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm1,
sparse_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm2) {
hm1.swap(hm2);
}
_END_GOOGLE_NAMESPACE_
#endif /* _SPARSE_HASH_MAP_H_ */

View file

@ -0,0 +1,338 @@
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
//
// This is just a very thin wrapper over sparsehashtable.h, just
// like sgi stl's stl_hash_set is a very thin wrapper over
// stl_hashtable. The major thing we define is operator[], because
// we have a concept of a data_type which stl_hashtable doesn't
// (it only has a key and a value).
//
// This is more different from sparse_hash_map than you might think,
// because all iterators for sets are const (you obviously can't
// change the key, and for sets there is no value).
//
// We adhere mostly to the STL semantics for hash-map. One important
// exception is that insert() may invalidate iterators entirely -- STL
// semantics are that insert() may reorder iterators, but they all
// still refer to something valid in the hashtable. Not so for us.
// Likewise, insert() may invalidate pointers into the hashtable.
// (Whether insert invalidates iterators and pointers depends on
// whether it results in a hashtable resize). On the plus side,
// delete() doesn't invalidate iterators or pointers at all, or even
// change the ordering of elements.
//
// Here are a few "power user" tips:
//
// 1) set_deleted_key():
// Unlike STL's hash_map, if you want to use erase() you
// *must* call set_deleted_key() after construction.
//
// 2) resize(0):
// When an item is deleted, its memory isn't freed right
// away. This allows you to iterate over a hashtable,
// and call erase(), without invalidating the iterator.
// To force the memory to be freed, call resize(0).
// For tr1 compatibility, this can also be called as rehash(0).
//
// 3) min_load_factor(0.0)
// Setting the minimum load factor to 0.0 guarantees that
// the hash table will never shrink.
//
// Roughly speaking:
// (1) dense_hash_set: fastest, uses the most memory unless entries are small
// (2) sparse_hash_set: slowest, uses the least memory
// (3) hash_set / unordered_set (STL): in the middle
//
// Typically I use sparse_hash_set when I care about space and/or when
// I need to save the hashtable on disk. I use hash_set otherwise. I
// don't personally use dense_hash_set ever; some people use it for
// small sets with lots of lookups.
//
// - dense_hash_set has, typically, about 78% memory overhead (if your
// data takes up X bytes, the hash_set uses .78X more bytes in overhead).
// - sparse_hash_set has about 4 bits overhead per entry.
// - sparse_hash_set can be 3-7 times slower than the others for lookup and,
// especially, inserts. See time_hash_map.cc for details.
//
// See /usr/(local/)?doc/sparsehash-*/sparse_hash_set.html
// for information about how to use this class.
#ifndef _SPARSE_HASH_SET_H_
#define _SPARSE_HASH_SET_H_
#include <sparsehash/internal/sparseconfig.h>
#include <algorithm> // needed by stl_alloc
#include <functional> // for equal_to<>
#include <memory> // for alloc (which we don't use)
#include <utility> // for pair<>
#include <sparsehash/internal/libc_allocator_with_realloc.h>
#include <sparsehash/internal/sparsehashtable.h> // IWYU pragma: export
#include HASH_FUN_H // for hash<>
_START_GOOGLE_NAMESPACE_
template <class Value,
class HashFcn = SPARSEHASH_HASH<Value>, // defined in sparseconfig.h
class EqualKey = std::equal_to<Value>,
class Alloc = libc_allocator_with_realloc<Value> >
class sparse_hash_set {
private:
// Apparently identity is not stl-standard, so we define our own
struct Identity {
typedef const Value& result_type;
const Value& operator()(const Value& v) const { return v; }
};
struct SetKey {
void operator()(Value* value, const Value& new_key) const {
*value = new_key;
}
};
typedef sparse_hashtable<Value, Value, HashFcn, Identity, SetKey,
EqualKey, Alloc> ht;
ht rep;
public:
typedef typename ht::key_type key_type;
typedef typename ht::value_type value_type;
typedef typename ht::hasher hasher;
typedef typename ht::key_equal key_equal;
typedef Alloc allocator_type;
typedef typename ht::size_type size_type;
typedef typename ht::difference_type difference_type;
typedef typename ht::const_pointer pointer;
typedef typename ht::const_pointer const_pointer;
typedef typename ht::const_reference reference;
typedef typename ht::const_reference const_reference;
typedef typename ht::const_iterator iterator;
typedef typename ht::const_iterator const_iterator;
typedef typename ht::const_local_iterator local_iterator;
typedef typename ht::const_local_iterator const_local_iterator;
// Iterator functions -- recall all iterators are const
iterator begin() const { return rep.begin(); }
iterator end() const { return rep.end(); }
// These come from tr1's unordered_set. For us, a bucket has 0 or 1 elements.
local_iterator begin(size_type i) const { return rep.begin(i); }
local_iterator end(size_type i) const { return rep.end(i); }
// Accessor functions
allocator_type get_allocator() const { return rep.get_allocator(); }
hasher hash_funct() const { return rep.hash_funct(); }
hasher hash_function() const { return hash_funct(); } // tr1 name
key_equal key_eq() const { return rep.key_eq(); }
// Constructors
explicit sparse_hash_set(size_type expected_max_items_in_table = 0,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
}
template <class InputIterator>
sparse_hash_set(InputIterator f, InputIterator l,
size_type expected_max_items_in_table = 0,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
rep.insert(f, l);
}
// We use the default copy constructor
// We use the default operator=()
// We use the default destructor
void clear() { rep.clear(); }
void swap(sparse_hash_set& hs) { rep.swap(hs.rep); }
// Functions concerning size
size_type size() const { return rep.size(); }
size_type max_size() const { return rep.max_size(); }
bool empty() const { return rep.empty(); }
size_type bucket_count() const { return rep.bucket_count(); }
size_type max_bucket_count() const { return rep.max_bucket_count(); }
// These are tr1 methods. bucket() is the bucket the key is or would be in.
size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
size_type bucket(const key_type& key) const { return rep.bucket(key); }
float load_factor() const {
return size() * 1.0f / bucket_count();
}
float max_load_factor() const {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
return grow;
}
void max_load_factor(float new_grow) {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
rep.set_resizing_parameters(shrink, new_grow);
}
// These aren't tr1 methods but perhaps ought to be.
float min_load_factor() const {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
return shrink;
}
void min_load_factor(float new_shrink) {
float shrink, grow;
rep.get_resizing_parameters(&shrink, &grow);
rep.set_resizing_parameters(new_shrink, grow);
}
// Deprecated; use min_load_factor() or max_load_factor() instead.
void set_resizing_parameters(float shrink, float grow) {
rep.set_resizing_parameters(shrink, grow);
}
void resize(size_type hint) { rep.resize(hint); }
void rehash(size_type hint) { resize(hint); } // the tr1 name
// Lookup routines
iterator find(const key_type& key) const { return rep.find(key); }
size_type count(const key_type& key) const { return rep.count(key); }
std::pair<iterator, iterator> equal_range(const key_type& key) const {
return rep.equal_range(key);
}
// Insertion routines
std::pair<iterator, bool> insert(const value_type& obj) {
std::pair<typename ht::iterator, bool> p = rep.insert(obj);
return std::pair<iterator, bool>(p.first, p.second); // const to non-const
}
template <class InputIterator> void insert(InputIterator f, InputIterator l) {
rep.insert(f, l);
}
void insert(const_iterator f, const_iterator l) {
rep.insert(f, l);
}
// Required for std::insert_iterator; the passed-in iterator is ignored.
iterator insert(iterator, const value_type& obj) {
return insert(obj).first;
}
// Deletion routines
// THESE ARE NON-STANDARD! I make you specify an "impossible" key
// value to identify deleted buckets. You can change the key as
// time goes on, or get rid of it entirely to be insert-only.
void set_deleted_key(const key_type& key) { rep.set_deleted_key(key); }
void clear_deleted_key() { rep.clear_deleted_key(); }
key_type deleted_key() const { return rep.deleted_key(); }
// These are standard
size_type erase(const key_type& key) { return rep.erase(key); }
void erase(iterator it) { rep.erase(it); }
void erase(iterator f, iterator l) { rep.erase(f, l); }
// Comparison
bool operator==(const sparse_hash_set& hs) const { return rep == hs.rep; }
bool operator!=(const sparse_hash_set& hs) const { return rep != hs.rep; }
// I/O -- this is an add-on for writing metainformation to disk
//
// For maximum flexibility, this does not assume a particular
// file type (though it will probably be a FILE *). We just pass
// the fp through to rep.
// If your keys and values are simple enough, you can pass this
// serializer to serialize()/unserialize(). "Simple enough" means
// value_type is a POD type that contains no pointers. Note,
// however, we don't try to normalize endianness.
typedef typename ht::NopointerSerializer NopointerSerializer;
// serializer: a class providing operator()(OUTPUT*, const value_type&)
// (writing value_type to OUTPUT). You can specify a
// NopointerSerializer object if appropriate (see above).
// fp: either a FILE*, OR an ostream*/subclass_of_ostream*, OR a
// pointer to a class providing size_t Write(const void*, size_t),
// which writes a buffer into a stream (which fp presumably
// owns) and returns the number of bytes successfully written.
// Note basic_ostream<not_char> is not currently supported.
template <typename ValueSerializer, typename OUTPUT>
bool serialize(ValueSerializer serializer, OUTPUT* fp) {
return rep.serialize(serializer, fp);
}
// serializer: a functor providing operator()(INPUT*, value_type*)
// (reading from INPUT and into value_type). You can specify a
// NopointerSerializer object if appropriate (see above).
// fp: either a FILE*, OR an istream*/subclass_of_istream*, OR a
// pointer to a class providing size_t Read(void*, size_t),
// which reads into a buffer from a stream (which fp presumably
// owns) and returns the number of bytes successfully read.
// Note basic_istream<not_char> is not currently supported.
// NOTE: Since value_type is const Key, ValueSerializer
// may need to do a const cast in order to fill in the key.
// NOTE: if Key is not a POD type, the serializer MUST use
// placement-new to initialize its value, rather than a normal
// equals-assignment or similar. (The value_type* passed into
// the serializer points to garbage memory.)
template <typename ValueSerializer, typename INPUT>
bool unserialize(ValueSerializer serializer, INPUT* fp) {
return rep.unserialize(serializer, fp);
}
// The four methods below are DEPRECATED.
// Use serialize() and unserialize() for new code.
template <typename OUTPUT>
bool write_metadata(OUTPUT *fp) { return rep.write_metadata(fp); }
template <typename INPUT>
bool read_metadata(INPUT *fp) { return rep.read_metadata(fp); }
template <typename OUTPUT>
bool write_nopointer_data(OUTPUT *fp) { return rep.write_nopointer_data(fp); }
template <typename INPUT>
bool read_nopointer_data(INPUT *fp) { return rep.read_nopointer_data(fp); }
};
template <class Val, class HashFcn, class EqualKey, class Alloc>
inline void swap(sparse_hash_set<Val, HashFcn, EqualKey, Alloc>& hs1,
sparse_hash_set<Val, HashFcn, EqualKey, Alloc>& hs2) {
hs1.swap(hs2);
}
_END_GOOGLE_NAMESPACE_
#endif /* _SPARSE_HASH_SET_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,134 @@
// Copyright 2005 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ----
//
// Template metaprogramming utility functions.
//
// This code is compiled directly on many platforms, including client
// platforms like Windows, Mac, and embedded systems. Before making
// any changes here, make sure that you're not breaking any platforms.
//
//
// The names choosen here reflect those used in tr1 and the boost::mpl
// library, there are similar operations used in the Loki library as
// well. I prefer the boost names for 2 reasons:
// 1. I think that portions of the Boost libraries are more likely to
// be included in the c++ standard.
// 2. It is not impossible that some of the boost libraries will be
// included in our own build in the future.
// Both of these outcomes means that we may be able to directly replace
// some of these with boost equivalents.
//
#ifndef BASE_TEMPLATE_UTIL_H_
#define BASE_TEMPLATE_UTIL_H_
#include <sparsehash/internal/sparseconfig.h>
_START_GOOGLE_NAMESPACE_
// Types small_ and big_ are guaranteed such that sizeof(small_) <
// sizeof(big_)
typedef char small_;
struct big_ {
char dummy[2];
};
// Identity metafunction.
template <class T>
struct identity_ {
typedef T type;
};
// integral_constant, defined in tr1, is a wrapper for an integer
// value. We don't really need this generality; we could get away
// with hardcoding the integer type to bool. We use the fully
// general integer_constant for compatibility with tr1.
template<class T, T v>
struct integral_constant {
static const T value = v;
typedef T value_type;
typedef integral_constant<T, v> type;
};
template <class T, T v> const T integral_constant<T, v>::value;
// Abbreviations: true_type and false_type are structs that represent boolean
// true and false values. Also define the boost::mpl versions of those names,
// true_ and false_.
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
typedef true_type true_;
typedef false_type false_;
// if_ is a templatized conditional statement.
// if_<cond, A, B> is a compile time evaluation of cond.
// if_<>::type contains A if cond is true, B otherwise.
template<bool cond, typename A, typename B>
struct if_{
typedef A type;
};
template<typename A, typename B>
struct if_<false, A, B> {
typedef B type;
};
// type_equals_ is a template type comparator, similar to Loki IsSameType.
// type_equals_<A, B>::value is true iff "A" is the same type as "B".
//
// New code should prefer base::is_same, defined in base/type_traits.h.
// It is functionally identical, but is_same is the standard spelling.
template<typename A, typename B>
struct type_equals_ : public false_ {
};
template<typename A>
struct type_equals_<A, A> : public true_ {
};
// and_ is a template && operator.
// and_<A, B>::value evaluates "A::value && B::value".
template<typename A, typename B>
struct and_ : public integral_constant<bool, (A::value && B::value)> {
};
// or_ is a template || operator.
// or_<A, B>::value evaluates "A::value || B::value".
template<typename A, typename B>
struct or_ : public integral_constant<bool, (A::value || B::value)> {
};
_END_GOOGLE_NAMESPACE_
#endif // BASE_TEMPLATE_UTIL_H_

View file

@ -0,0 +1,342 @@
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ----
//
// This code is compiled directly on many platforms, including client
// platforms like Windows, Mac, and embedded systems. Before making
// any changes here, make sure that you're not breaking any platforms.
//
// Define a small subset of tr1 type traits. The traits we define are:
// is_integral
// is_floating_point
// is_pointer
// is_enum
// is_reference
// is_pod
// has_trivial_constructor
// has_trivial_copy
// has_trivial_assign
// has_trivial_destructor
// remove_const
// remove_volatile
// remove_cv
// remove_reference
// add_reference
// remove_pointer
// is_same
// is_convertible
// We can add more type traits as required.
#ifndef BASE_TYPE_TRAITS_H_
#define BASE_TYPE_TRAITS_H_
#include <sparsehash/internal/sparseconfig.h>
#include <utility> // For pair
#include <sparsehash/template_util.h> // For true_type and false_type
_START_GOOGLE_NAMESPACE_
template <class T> struct is_integral;
template <class T> struct is_floating_point;
template <class T> struct is_pointer;
// MSVC can't compile this correctly, and neither can gcc 3.3.5 (at least)
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
// is_enum uses is_convertible, which is not available on MSVC.
template <class T> struct is_enum;
#endif
template <class T> struct is_reference;
template <class T> struct is_pod;
template <class T> struct has_trivial_constructor;
template <class T> struct has_trivial_copy;
template <class T> struct has_trivial_assign;
template <class T> struct has_trivial_destructor;
template <class T> struct remove_const;
template <class T> struct remove_volatile;
template <class T> struct remove_cv;
template <class T> struct remove_reference;
template <class T> struct add_reference;
template <class T> struct remove_pointer;
template <class T, class U> struct is_same;
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
template <class From, class To> struct is_convertible;
#endif
// is_integral is false except for the built-in integer types. A
// cv-qualified type is integral if and only if the underlying type is.
template <class T> struct is_integral : false_type { };
template<> struct is_integral<bool> : true_type { };
template<> struct is_integral<char> : true_type { };
template<> struct is_integral<unsigned char> : true_type { };
template<> struct is_integral<signed char> : true_type { };
#if defined(_MSC_VER)
// wchar_t is not by default a distinct type from unsigned short in
// Microsoft C.
// See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx
template<> struct is_integral<__wchar_t> : true_type { };
#else
template<> struct is_integral<wchar_t> : true_type { };
#endif
template<> struct is_integral<short> : true_type { };
template<> struct is_integral<unsigned short> : true_type { };
template<> struct is_integral<int> : true_type { };
template<> struct is_integral<unsigned int> : true_type { };
template<> struct is_integral<long> : true_type { };
template<> struct is_integral<unsigned long> : true_type { };
#ifdef HAVE_LONG_LONG
template<> struct is_integral<long long> : true_type { };
template<> struct is_integral<unsigned long long> : true_type { };
#endif
template <class T> struct is_integral<const T> : is_integral<T> { };
template <class T> struct is_integral<volatile T> : is_integral<T> { };
template <class T> struct is_integral<const volatile T> : is_integral<T> { };
// is_floating_point is false except for the built-in floating-point types.
// A cv-qualified type is integral if and only if the underlying type is.
template <class T> struct is_floating_point : false_type { };
template<> struct is_floating_point<float> : true_type { };
template<> struct is_floating_point<double> : true_type { };
template<> struct is_floating_point<long double> : true_type { };
template <class T> struct is_floating_point<const T>
: is_floating_point<T> { };
template <class T> struct is_floating_point<volatile T>
: is_floating_point<T> { };
template <class T> struct is_floating_point<const volatile T>
: is_floating_point<T> { };
// is_pointer is false except for pointer types. A cv-qualified type (e.g.
// "int* const", as opposed to "int const*") is cv-qualified if and only if
// the underlying type is.
template <class T> struct is_pointer : false_type { };
template <class T> struct is_pointer<T*> : true_type { };
template <class T> struct is_pointer<const T> : is_pointer<T> { };
template <class T> struct is_pointer<volatile T> : is_pointer<T> { };
template <class T> struct is_pointer<const volatile T> : is_pointer<T> { };
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
namespace internal {
template <class T> struct is_class_or_union {
template <class U> static small_ tester(void (U::*)());
template <class U> static big_ tester(...);
static const bool value = sizeof(tester<T>(0)) == sizeof(small_);
};
// is_convertible chokes if the first argument is an array. That's why
// we use add_reference here.
template <bool NotUnum, class T> struct is_enum_impl
: is_convertible<typename add_reference<T>::type, int> { };
template <class T> struct is_enum_impl<true, T> : false_type { };
} // namespace internal
// Specified by TR1 [4.5.1] primary type categories.
// Implementation note:
//
// Each type is either void, integral, floating point, array, pointer,
// reference, member object pointer, member function pointer, enum,
// union or class. Out of these, only integral, floating point, reference,
// class and enum types are potentially convertible to int. Therefore,
// if a type is not a reference, integral, floating point or class and
// is convertible to int, it's a enum. Adding cv-qualification to a type
// does not change whether it's an enum.
//
// Is-convertible-to-int check is done only if all other checks pass,
// because it can't be used with some types (e.g. void or classes with
// inaccessible conversion operators).
template <class T> struct is_enum
: internal::is_enum_impl<
is_same<T, void>::value ||
is_integral<T>::value ||
is_floating_point<T>::value ||
is_reference<T>::value ||
internal::is_class_or_union<T>::value,
T> { };
template <class T> struct is_enum<const T> : is_enum<T> { };
template <class T> struct is_enum<volatile T> : is_enum<T> { };
template <class T> struct is_enum<const volatile T> : is_enum<T> { };
#endif
// is_reference is false except for reference types.
template<typename T> struct is_reference : false_type {};
template<typename T> struct is_reference<T&> : true_type {};
// We can't get is_pod right without compiler help, so fail conservatively.
// We will assume it's false except for arithmetic types, enumerations,
// pointers and cv-qualified versions thereof. Note that std::pair<T,U>
// is not a POD even if T and U are PODs.
template <class T> struct is_pod
: integral_constant<bool, (is_integral<T>::value ||
is_floating_point<T>::value ||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
// is_enum is not available on MSVC.
is_enum<T>::value ||
#endif
is_pointer<T>::value)> { };
template <class T> struct is_pod<const T> : is_pod<T> { };
template <class T> struct is_pod<volatile T> : is_pod<T> { };
template <class T> struct is_pod<const volatile T> : is_pod<T> { };
// We can't get has_trivial_constructor right without compiler help, so
// fail conservatively. We will assume it's false except for: (1) types
// for which is_pod is true. (2) std::pair of types with trivial
// constructors. (3) array of a type with a trivial constructor.
// (4) const versions thereof.
template <class T> struct has_trivial_constructor : is_pod<T> { };
template <class T, class U> struct has_trivial_constructor<std::pair<T, U> >
: integral_constant<bool,
(has_trivial_constructor<T>::value &&
has_trivial_constructor<U>::value)> { };
template <class A, int N> struct has_trivial_constructor<A[N]>
: has_trivial_constructor<A> { };
template <class T> struct has_trivial_constructor<const T>
: has_trivial_constructor<T> { };
// We can't get has_trivial_copy right without compiler help, so fail
// conservatively. We will assume it's false except for: (1) types
// for which is_pod is true. (2) std::pair of types with trivial copy
// constructors. (3) array of a type with a trivial copy constructor.
// (4) const versions thereof.
template <class T> struct has_trivial_copy : is_pod<T> { };
template <class T, class U> struct has_trivial_copy<std::pair<T, U> >
: integral_constant<bool,
(has_trivial_copy<T>::value &&
has_trivial_copy<U>::value)> { };
template <class A, int N> struct has_trivial_copy<A[N]>
: has_trivial_copy<A> { };
template <class T> struct has_trivial_copy<const T> : has_trivial_copy<T> { };
// We can't get has_trivial_assign right without compiler help, so fail
// conservatively. We will assume it's false except for: (1) types
// for which is_pod is true. (2) std::pair of types with trivial copy
// constructors. (3) array of a type with a trivial assign constructor.
template <class T> struct has_trivial_assign : is_pod<T> { };
template <class T, class U> struct has_trivial_assign<std::pair<T, U> >
: integral_constant<bool,
(has_trivial_assign<T>::value &&
has_trivial_assign<U>::value)> { };
template <class A, int N> struct has_trivial_assign<A[N]>
: has_trivial_assign<A> { };
// We can't get has_trivial_destructor right without compiler help, so
// fail conservatively. We will assume it's false except for: (1) types
// for which is_pod is true. (2) std::pair of types with trivial
// destructors. (3) array of a type with a trivial destructor.
// (4) const versions thereof.
template <class T> struct has_trivial_destructor : is_pod<T> { };
template <class T, class U> struct has_trivial_destructor<std::pair<T, U> >
: integral_constant<bool,
(has_trivial_destructor<T>::value &&
has_trivial_destructor<U>::value)> { };
template <class A, int N> struct has_trivial_destructor<A[N]>
: has_trivial_destructor<A> { };
template <class T> struct has_trivial_destructor<const T>
: has_trivial_destructor<T> { };
// Specified by TR1 [4.7.1]
template<typename T> struct remove_const { typedef T type; };
template<typename T> struct remove_const<T const> { typedef T type; };
template<typename T> struct remove_volatile { typedef T type; };
template<typename T> struct remove_volatile<T volatile> { typedef T type; };
template<typename T> struct remove_cv {
typedef typename remove_const<typename remove_volatile<T>::type>::type type;
};
// Specified by TR1 [4.7.2] Reference modifications.
template<typename T> struct remove_reference { typedef T type; };
template<typename T> struct remove_reference<T&> { typedef T type; };
template <typename T> struct add_reference { typedef T& type; };
template <typename T> struct add_reference<T&> { typedef T& type; };
// Specified by TR1 [4.7.4] Pointer modifications.
template<typename T> struct remove_pointer { typedef T type; };
template<typename T> struct remove_pointer<T*> { typedef T type; };
template<typename T> struct remove_pointer<T* const> { typedef T type; };
template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
template<typename T> struct remove_pointer<T* const volatile> {
typedef T type; };
// Specified by TR1 [4.6] Relationships between types
template<typename T, typename U> struct is_same : public false_type { };
template<typename T> struct is_same<T, T> : public true_type { };
// Specified by TR1 [4.6] Relationships between types
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
namespace internal {
// This class is an implementation detail for is_convertible, and you
// don't need to know how it works to use is_convertible. For those
// who care: we declare two different functions, one whose argument is
// of type To and one with a variadic argument list. We give them
// return types of different size, so we can use sizeof to trick the
// compiler into telling us which function it would have chosen if we
// had called it with an argument of type From. See Alexandrescu's
// _Modern C++ Design_ for more details on this sort of trick.
template <typename From, typename To>
struct ConvertHelper {
static small_ Test(To);
static big_ Test(...);
static From Create();
};
} // namespace internal
// Inherits from true_type if From is convertible to To, false_type otherwise.
template <typename From, typename To>
struct is_convertible
: integral_constant<bool,
sizeof(internal::ConvertHelper<From, To>::Test(
internal::ConvertHelper<From, To>::Create()))
== sizeof(small_)> {
};
#endif
_END_GOOGLE_NAMESPACE_
// Right now these macros are no-ops, and mostly just document the fact
// these types are PODs, for human use. They may be made more contentful
// later. The typedef is just to make it legal to put a semicolon after
// these macros.
#define DECLARE_POD(TypeName) typedef int Dummy_Type_For_DECLARE_POD
#define DECLARE_NESTED_POD(TypeName) DECLARE_POD(TypeName)
#define PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT(TemplateName) \
typedef int Dummy_Type_For_PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT
#define ENFORCE_POD(TypeName) typedef int Dummy_Type_For_ENFORCE_POD
#endif // BASE_TYPE_TRAITS_H_

View file

@ -0,0 +1,978 @@
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
//
// Since sparsetable is templatized, it's important that we test every
// function in every class in this file -- not just to see if it
// works, but even if it compiles.
#include <sparsehash/internal/sparseconfig.h>
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h> // for size_t
#include <stdlib.h> // defines unlink() on some windows platforms(?)
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif // for unlink()
#include <memory> // for allocator
#include <string>
#include <sparsehash/sparsetable>
using std::string;
using std::allocator;
using GOOGLE_NAMESPACE::sparsetable;
using GOOGLE_NAMESPACE::DEFAULT_SPARSEGROUP_SIZE;
typedef u_int16_t uint16;
string FLAGS_test_tmpdir = "/tmp/";
// Many sparsetable operations return a size_t. Rather than have to
// use PRIuS everywhere, we'll just cast to a "big enough" value.
#define UL(x) ( static_cast<unsigned long>(x) )
static char outbuf[10240]; // big enough for these tests
static char* out = outbuf; // where to write next
#define LEFT (outbuf + sizeof(outbuf) - out)
#define TEST(cond) out += snprintf(out, LEFT, #cond "? %s\n", \
(cond) ? "yes" : "no");
inline string AsString(int n) {
const int N = 64;
char buf[N];
snprintf(buf, N, "%d", n);
return string(buf);
}
// Test sparsetable with a POD type, int.
void TestInt() {
out += snprintf(out, LEFT, "int test\n");
sparsetable<int> x(7), y(70), z;
x.set(4, 10);
y.set(12, -12);
y.set(47, -47);
y.set(48, -48);
y.set(49, -49);
const sparsetable<int> constx(x);
const sparsetable<int> consty(y);
// ----------------------------------------------------------------------
// Test the plain iterators
for ( sparsetable<int>::iterator it = x.begin(); it != x.end(); ++it ) {
out += snprintf(out, LEFT, "x[%lu]: %d\n", UL(it - x.begin()), int(*it));
}
for ( sparsetable<int>::const_iterator it = x.begin(); it != x.end(); ++it ) {
out += snprintf(out, LEFT, "x[%lu]: %d\n", UL(it - x.begin()), *it);
}
for ( sparsetable<int>::reverse_iterator it = x.rbegin(); it != x.rend(); ++it ) {
out += snprintf(out, LEFT, "x[%lu]: %d\n", UL(x.rend()-1 - it), int(*it));
}
for ( sparsetable<int>::const_reverse_iterator it = constx.rbegin(); it != constx.rend(); ++it ) {
out += snprintf(out, LEFT, "x[%lu]: %d\n", UL(constx.rend()-1 - it), *it);
}
for ( sparsetable<int>::iterator it = z.begin(); it != z.end(); ++it ) {
out += snprintf(out, LEFT, "z[%lu]: %d\n", UL(it - z.begin()), int(*it));
}
{ // array version
out += snprintf(out, LEFT, "x[3]: %d\n", int(x[3]));
out += snprintf(out, LEFT, "x[4]: %d\n", int(x[4]));
out += snprintf(out, LEFT, "x[5]: %d\n", int(x[5]));
}
{
sparsetable<int>::iterator it; // non-const version
out += snprintf(out, LEFT, "x[4]: %d\n", int(x.begin()[4]));
it = x.begin() + 4; // should point to the non-zero value
out += snprintf(out, LEFT, "x[4]: %d\n", int(*it));
it--;
--it;
it += 5;
it -= 2;
it++;
++it;
it = it - 3;
it = 1 + it; // now at 5
out += snprintf(out, LEFT, "x[3]: %d\n", int(it[-2]));
out += snprintf(out, LEFT, "x[4]: %d\n", int(it[-1]));
*it = 55;
out += snprintf(out, LEFT, "x[5]: %d\n", int(it[0]));
out += snprintf(out, LEFT, "x[5]: %d\n", int(*it));
int *x6 = &(it[1]);
*x6 = 66;
out += snprintf(out, LEFT, "x[6]: %d\n", int(*(it + 1)));
// Let's test comparitors as well
TEST(it == it);
TEST(!(it != it));
TEST(!(it < it));
TEST(!(it > it));
TEST(it <= it);
TEST(it >= it);
sparsetable<int>::iterator it_minus_1 = it - 1;
TEST(!(it == it_minus_1));
TEST(it != it_minus_1);
TEST(!(it < it_minus_1));
TEST(it > it_minus_1);
TEST(!(it <= it_minus_1));
TEST(it >= it_minus_1);
TEST(!(it_minus_1 == it));
TEST(it_minus_1 != it);
TEST(it_minus_1 < it);
TEST(!(it_minus_1 > it));
TEST(it_minus_1 <= it);
TEST(!(it_minus_1 >= it));
sparsetable<int>::iterator it_plus_1 = it + 1;
TEST(!(it == it_plus_1));
TEST(it != it_plus_1);
TEST(it < it_plus_1);
TEST(!(it > it_plus_1));
TEST(it <= it_plus_1);
TEST(!(it >= it_plus_1));
TEST(!(it_plus_1 == it));
TEST(it_plus_1 != it);
TEST(!(it_plus_1 < it));
TEST(it_plus_1 > it);
TEST(!(it_plus_1 <= it));
TEST(it_plus_1 >= it);
}
{
sparsetable<int>::const_iterator it; // const version
out += snprintf(out, LEFT, "x[4]: %d\n", int(x.begin()[4]));
it = x.begin() + 4; // should point to the non-zero value
out += snprintf(out, LEFT, "x[4]: %d\n", *it);
it--;
--it;
it += 5;
it -= 2;
it++;
++it;
it = it - 3;
it = 1 + it; // now at 5
out += snprintf(out, LEFT, "x[3]: %d\n", it[-2]);
out += snprintf(out, LEFT, "x[4]: %d\n", it[-1]);
out += snprintf(out, LEFT, "x[5]: %d\n", *it);
out += snprintf(out, LEFT, "x[6]: %d\n", *(it + 1));
// Let's test comparitors as well
TEST(it == it);
TEST(!(it != it));
TEST(!(it < it));
TEST(!(it > it));
TEST(it <= it);
TEST(it >= it);
sparsetable<int>::const_iterator it_minus_1 = it - 1;
TEST(!(it == it_minus_1));
TEST(it != it_minus_1);
TEST(!(it < it_minus_1));
TEST(it > it_minus_1);
TEST(!(it <= it_minus_1));
TEST(it >= it_minus_1);
TEST(!(it_minus_1 == it));
TEST(it_minus_1 != it);
TEST(it_minus_1 < it);
TEST(!(it_minus_1 > it));
TEST(it_minus_1 <= it);
TEST(!(it_minus_1 >= it));
sparsetable<int>::const_iterator it_plus_1 = it + 1;
TEST(!(it == it_plus_1));
TEST(it != it_plus_1);
TEST(it < it_plus_1);
TEST(!(it > it_plus_1));
TEST(it <= it_plus_1);
TEST(!(it >= it_plus_1));
TEST(!(it_plus_1 == it));
TEST(it_plus_1 != it);
TEST(!(it_plus_1 < it));
TEST(it_plus_1 > it);
TEST(!(it_plus_1 <= it));
TEST(it_plus_1 >= it);
}
TEST(x.begin() == x.begin() + 1 - 1);
TEST(x.begin() < x.end());
TEST(z.begin() < z.end());
TEST(z.begin() <= z.end());
TEST(z.begin() == z.end());
// ----------------------------------------------------------------------
// Test the non-empty iterators
for ( sparsetable<int>::nonempty_iterator it = x.nonempty_begin(); it != x.nonempty_end(); ++it ) {
out += snprintf(out, LEFT, "x[??]: %d\n", *it);
}
for ( sparsetable<int>::const_nonempty_iterator it = y.nonempty_begin(); it != y.nonempty_end(); ++it ) {
out += snprintf(out, LEFT, "y[??]: %d\n", *it);
}
for ( sparsetable<int>::reverse_nonempty_iterator it = y.nonempty_rbegin(); it != y.nonempty_rend(); ++it ) {
out += snprintf(out, LEFT, "y[??]: %d\n", *it);
}
for ( sparsetable<int>::const_reverse_nonempty_iterator it = consty.nonempty_rbegin(); it != consty.nonempty_rend(); ++it ) {
out += snprintf(out, LEFT, "y[??]: %d\n", *it);
}
for ( sparsetable<int>::nonempty_iterator it = z.nonempty_begin(); it != z.nonempty_end(); ++it ) {
out += snprintf(out, LEFT, "z[??]: %d\n", *it);
}
{
sparsetable<int>::nonempty_iterator it; // non-const version
out += snprintf(out, LEFT, "first non-empty y: %d\n", *y.nonempty_begin());
out += snprintf(out, LEFT, "first non-empty x: %d\n", *x.nonempty_begin());
it = x.nonempty_begin();
++it; // should be at end
--it;
out += snprintf(out, LEFT, "first non-empty x: %d\n", *it++);
it--;
out += snprintf(out, LEFT, "first non-empty x: %d\n", *it++);
}
{
sparsetable<int>::const_nonempty_iterator it; // non-const version
out += snprintf(out, LEFT, "first non-empty y: %d\n", *y.nonempty_begin());
out += snprintf(out, LEFT, "first non-empty x: %d\n", *x.nonempty_begin());
it = x.nonempty_begin();
++it; // should be at end
--it;
out += snprintf(out, LEFT, "first non-empty x: %d\n", *it++);
it--;
out += snprintf(out, LEFT, "first non-empty x: %d\n", *it++);
}
TEST(x.begin() == x.begin() + 1 - 1);
TEST(z.begin() != z.end());
// ----------------------------------------------------------------------
// Test the non-empty iterators get_pos function
sparsetable<unsigned int> gp(100);
for (int i = 0; i < 100; i += 9) {
gp.set(i,i);
}
for (sparsetable<unsigned int>::const_nonempty_iterator
it = gp.nonempty_begin(); it != gp.nonempty_end(); ++it) {
out += snprintf(out, LEFT,
"get_pos() for const nonempty_iterator: %u == %lu\n",
*it, UL(gp.get_pos(it)));
}
for (sparsetable<unsigned int>::nonempty_iterator
it = gp.nonempty_begin(); it != gp.nonempty_end(); ++it) {
out += snprintf(out, LEFT,
"get_pos() for nonempty_iterator: %u == %lu\n",
*it, UL(gp.get_pos(it)));
}
// ----------------------------------------------------------------------
// Test sparsetable functions
out += snprintf(out, LEFT, "x has %lu/%lu buckets, "
"y %lu/%lu, z %lu/%lu\n",
UL(x.num_nonempty()), UL(x.size()),
UL(y.num_nonempty()), UL(y.size()),
UL(z.num_nonempty()), UL(z.size()));
y.resize(48); // should get rid of 48 and 49
y.resize(70); // 48 and 49 should still be gone
out += snprintf(out, LEFT, "y shrank and grew: it's now %lu/%lu\n",
UL(y.num_nonempty()), UL(y.size()));
out += snprintf(out, LEFT, "y[12] = %d, y.get(12) = %d\n", int(y[12]), y.get(12));
y.erase(12);
out += snprintf(out, LEFT, "y[12] cleared. y now %lu/%lu. "
"y[12] = %d, y.get(12) = %d\n",
UL(y.num_nonempty()), UL(y.size()), int(y[12]), y.get(12));
swap(x, y);
y.clear();
TEST(y == z);
y.resize(70);
for ( int i = 10; i < 40; ++i )
y[i] = -i;
y.erase(y.begin() + 15, y.begin() + 30);
y.erase(y.begin() + 34);
y.erase(12);
y.resize(38);
y.resize(10000);
y[9898] = -9898;
for ( sparsetable<int>::const_iterator it = y.begin(); it != y.end(); ++it ) {
if ( y.test(it) )
out += snprintf(out, LEFT, "y[%lu] is set\n", UL(it - y.begin()));
}
out += snprintf(out, LEFT, "That's %lu set buckets\n", UL(y.num_nonempty()));
out += snprintf(out, LEFT, "Starting from y[32]...\n");
for ( sparsetable<int>::const_nonempty_iterator it = y.get_iter(32);
it != y.nonempty_end(); ++it )
out += snprintf(out, LEFT, "y[??] = %d\n", *it);
out += snprintf(out, LEFT, "From y[32] down...\n");
for ( sparsetable<int>::nonempty_iterator it = y.get_iter(32);
it != y.nonempty_begin(); )
out += snprintf(out, LEFT, "y[??] = %d\n", *--it);
// ----------------------------------------------------------------------
// Test I/O using deprecated read/write_metadata
string filestr = FLAGS_test_tmpdir + "/.sparsetable.test";
const char *file = filestr.c_str();
FILE *fp = fopen(file, "wb");
if ( fp == NULL ) {
// maybe we can't write to /tmp/. Try the current directory
file = ".sparsetable.test";
fp = fopen(file, "wb");
}
if ( fp == NULL ) {
out += snprintf(out, LEFT, "Can't open %s, skipping disk write...\n", file);
} else {
y.write_metadata(fp); // only write meta-information
y.write_nopointer_data(fp);
fclose(fp);
}
fp = fopen(file, "rb");
if ( fp == NULL ) {
out += snprintf(out, LEFT, "Can't open %s, skipping disk read...\n", file);
} else {
sparsetable<int> y2;
y2.read_metadata(fp);
y2.read_nopointer_data(fp);
fclose(fp);
for ( sparsetable<int>::const_iterator it = y2.begin(); it != y2.end(); ++it ) {
if ( y2.test(it) )
out += snprintf(out, LEFT, "y2[%lu] is %d\n", UL(it - y2.begin()), *it);
}
out += snprintf(out, LEFT, "That's %lu set buckets\n", UL(y2.num_nonempty()));
}
unlink(file);
// ----------------------------------------------------------------------
// Also test I/O using serialize()/unserialize()
fp = fopen(file, "wb");
if ( fp == NULL ) {
out += snprintf(out, LEFT, "Can't open %s, skipping disk write...\n", file);
} else {
y.serialize(sparsetable<int>::NopointerSerializer(), fp);
fclose(fp);
}
fp = fopen(file, "rb");
if ( fp == NULL ) {
out += snprintf(out, LEFT, "Can't open %s, skipping disk read...\n", file);
} else {
sparsetable<int> y2;
y2.unserialize(sparsetable<int>::NopointerSerializer(), fp);
fclose(fp);
for ( sparsetable<int>::const_iterator it = y2.begin(); it != y2.end(); ++it ) {
if ( y2.test(it) )
out += snprintf(out, LEFT, "y2[%lu] is %d\n", UL(it - y2.begin()), *it);
}
out += snprintf(out, LEFT, "That's %lu set buckets\n", UL(y2.num_nonempty()));
}
unlink(file);
}
// Test sparsetable with a non-POD type, std::string
void TestString() {
out += snprintf(out, LEFT, "string test\n");
sparsetable<string> x(7), y(70), z;
x.set(4, "foo");
y.set(12, "orange");
y.set(47, "grape");
y.set(48, "pear");
y.set(49, "apple");
// ----------------------------------------------------------------------
// Test the plain iterators
for ( sparsetable<string>::iterator it = x.begin(); it != x.end(); ++it ) {
out += snprintf(out, LEFT, "x[%lu]: %s\n",
UL(it - x.begin()), static_cast<string>(*it).c_str());
}
for ( sparsetable<string>::iterator it = z.begin(); it != z.end(); ++it ) {
out += snprintf(out, LEFT, "z[%lu]: %s\n",
UL(it - z.begin()), static_cast<string>(*it).c_str());
}
TEST(x.begin() == x.begin() + 1 - 1);
TEST(x.begin() < x.end());
TEST(z.begin() < z.end());
TEST(z.begin() <= z.end());
TEST(z.begin() == z.end());
// ----------------------------------------------------------------------
// Test the non-empty iterators
for ( sparsetable<string>::nonempty_iterator it = x.nonempty_begin(); it != x.nonempty_end(); ++it ) {
out += snprintf(out, LEFT, "x[??]: %s\n", it->c_str());
}
for ( sparsetable<string>::const_nonempty_iterator it = y.nonempty_begin(); it != y.nonempty_end(); ++it ) {
out += snprintf(out, LEFT, "y[??]: %s\n", it->c_str());
}
for ( sparsetable<string>::nonempty_iterator it = z.nonempty_begin(); it != z.nonempty_end(); ++it ) {
out += snprintf(out, LEFT, "z[??]: %s\n", it->c_str());
}
// ----------------------------------------------------------------------
// Test sparsetable functions
out += snprintf(out, LEFT, "x has %lu/%lu buckets, y %lu/%lu, z %lu/%lu\n",
UL(x.num_nonempty()), UL(x.size()),
UL(y.num_nonempty()), UL(y.size()),
UL(z.num_nonempty()), UL(z.size()));
y.resize(48); // should get rid of 48 and 49
y.resize(70); // 48 and 49 should still be gone
out += snprintf(out, LEFT, "y shrank and grew: it's now %lu/%lu\n",
UL(y.num_nonempty()), UL(y.size()));
out += snprintf(out, LEFT, "y[12] = %s, y.get(12) = %s\n",
static_cast<string>(y[12]).c_str(), y.get(12).c_str());
y.erase(12);
out += snprintf(out, LEFT, "y[12] cleared. y now %lu/%lu. "
"y[12] = %s, y.get(12) = %s\n",
UL(y.num_nonempty()), UL(y.size()),
static_cast<string>(y[12]).c_str(),
static_cast<string>(y.get(12)).c_str());
swap(x, y);
y.clear();
TEST(y == z);
y.resize(70);
for ( int i = 10; i < 40; ++i )
y.set(i, AsString(-i));
y.erase(y.begin() + 15, y.begin() + 30);
y.erase(y.begin() + 34);
y.erase(12);
y.resize(38);
y.resize(10000);
y.set(9898, AsString(-9898));
for ( sparsetable<string>::const_iterator it = y.begin(); it != y.end(); ++it ) {
if ( y.test(it) )
out += snprintf(out, LEFT, "y[%lu] is set\n", UL(it - y.begin()));
}
out += snprintf(out, LEFT, "That's %lu set buckets\n", UL(y.num_nonempty()));
out += snprintf(out, LEFT, "Starting from y[32]...\n");
for ( sparsetable<string>::const_nonempty_iterator it = y.get_iter(32);
it != y.nonempty_end(); ++it )
out += snprintf(out, LEFT, "y[??] = %s\n", it->c_str());
out += snprintf(out, LEFT, "From y[32] down...\n");
for ( sparsetable<string>::nonempty_iterator it = y.get_iter(32);
it != y.nonempty_begin(); )
out += snprintf(out, LEFT, "y[??] = %s\n", (*--it).c_str());
}
// An instrumented allocator that keeps track of all calls to
// allocate/deallocate/construct/destroy. It stores the number of times
// they were called and the values they were called with. Such information is
// stored in the following global variables.
static size_t sum_allocate_bytes;
static size_t sum_deallocate_bytes;
void ResetAllocatorCounters() {
sum_allocate_bytes = 0;
sum_deallocate_bytes = 0;
}
template <class T> class instrumented_allocator {
public:
typedef T value_type;
typedef uint16 size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
instrumented_allocator() {}
instrumented_allocator(const instrumented_allocator&) {}
~instrumented_allocator() {}
pointer address(reference r) const { return &r; }
const_pointer address(const_reference r) const { return &r; }
pointer allocate(size_type n, const_pointer = 0) {
sum_allocate_bytes += n * sizeof(value_type);
return static_cast<pointer>(malloc(n * sizeof(value_type)));
}
void deallocate(pointer p, size_type n) {
sum_deallocate_bytes += n * sizeof(value_type);
free(p);
}
size_type max_size() const {
return static_cast<size_type>(-1) / sizeof(value_type);
}
void construct(pointer p, const value_type& val) {
new(p) value_type(val);
}
void destroy(pointer p) {
p->~value_type();
}
template <class U>
explicit instrumented_allocator(const instrumented_allocator<U>&) {}
template<class U>
struct rebind {
typedef instrumented_allocator<U> other;
};
private:
void operator=(const instrumented_allocator&);
};
template<class T>
inline bool operator==(const instrumented_allocator<T>&,
const instrumented_allocator<T>&) {
return true;
}
template<class T>
inline bool operator!=(const instrumented_allocator<T>&,
const instrumented_allocator<T>&) {
return false;
}
// Test sparsetable with instrumented_allocator.
void TestAllocator() {
out += snprintf(out, LEFT, "allocator test\n");
ResetAllocatorCounters();
// POD (int32) with instrumented_allocator.
typedef sparsetable<int, DEFAULT_SPARSEGROUP_SIZE,
instrumented_allocator<int> > IntSparseTable;
IntSparseTable* s1 = new IntSparseTable(10000);
TEST(sum_allocate_bytes > 0);
for (int i = 0; i < 10000; ++i) {
s1->set(i, 0);
}
TEST(sum_allocate_bytes >= 10000 * sizeof(int));
ResetAllocatorCounters();
delete s1;
TEST(sum_deallocate_bytes >= 10000 * sizeof(int));
IntSparseTable* s2 = new IntSparseTable(1000);
IntSparseTable* s3 = new IntSparseTable(1000);
for (int i = 0; i < 1000; ++i) {
s2->set(i, 0);
s3->set(i, 0);
}
TEST(sum_allocate_bytes >= 2000 * sizeof(int));
ResetAllocatorCounters();
s3->clear();
TEST(sum_deallocate_bytes >= 1000 * sizeof(int));
ResetAllocatorCounters();
s2->swap(*s3); // s2 is empty after the swap
s2->clear();
TEST(sum_deallocate_bytes < 1000 * sizeof(int));
for (int i = 0; i < s3->size(); ++i) {
s3->erase(i);
}
TEST(sum_deallocate_bytes >= 1000 * sizeof(int));
delete s2;
delete s3;
// POD (int) with default allocator.
sparsetable<int> x, y;
for (int s = 1000; s <= 40000; s += 1000) {
x.resize(s);
for (int i = 0; i < s; ++i) {
x.set(i, i + 1);
}
y = x;
for (int i = 0; i < s; ++i) {
y.erase(i);
}
y.swap(x);
}
TEST(x.num_nonempty() == 0);
out += snprintf(out, LEFT, "y[0]: %d\n", int(y[0]));
out += snprintf(out, LEFT, "y[39999]: %d\n", int(y[39999]));
y.clear();
// POD (int) with std allocator.
sparsetable<int, DEFAULT_SPARSEGROUP_SIZE, allocator<int> > u, v;
for (int s = 1000; s <= 40000; s += 1000) {
u.resize(s);
for (int i = 0; i < s; ++i) {
u.set(i, i + 1);
}
v = u;
for (int i = 0; i < s; ++i) {
v.erase(i);
}
v.swap(u);
}
TEST(u.num_nonempty() == 0);
out += snprintf(out, LEFT, "v[0]: %d\n", int(v[0]));
out += snprintf(out, LEFT, "v[39999]: %d\n", int(v[39999]));
v.clear();
// Non-POD (string) with default allocator.
sparsetable<string> a, b;
for (int s = 1000; s <= 40000; s += 1000) {
a.resize(s);
for (int i = 0; i < s; ++i) {
a.set(i, "aa");
}
b = a;
for (int i = 0; i < s; ++i) {
b.erase(i);
}
b.swap(a);
}
TEST(a.num_nonempty() == 0);
out += snprintf(out, LEFT, "b[0]: %s\n", b.get(0).c_str());
out += snprintf(out, LEFT, "b[39999]: %s\n", b.get(39999).c_str());
b.clear();
}
// The expected output from all of the above: TestInt(), TestString() and
// TestAllocator().
static const char g_expected[] = (
"int test\n"
"x[0]: 0\n"
"x[1]: 0\n"
"x[2]: 0\n"
"x[3]: 0\n"
"x[4]: 10\n"
"x[5]: 0\n"
"x[6]: 0\n"
"x[0]: 0\n"
"x[1]: 0\n"
"x[2]: 0\n"
"x[3]: 0\n"
"x[4]: 10\n"
"x[5]: 0\n"
"x[6]: 0\n"
"x[6]: 0\n"
"x[5]: 0\n"
"x[4]: 10\n"
"x[3]: 0\n"
"x[2]: 0\n"
"x[1]: 0\n"
"x[0]: 0\n"
"x[6]: 0\n"
"x[5]: 0\n"
"x[4]: 10\n"
"x[3]: 0\n"
"x[2]: 0\n"
"x[1]: 0\n"
"x[0]: 0\n"
"x[3]: 0\n"
"x[4]: 10\n"
"x[5]: 0\n"
"x[4]: 10\n"
"x[4]: 10\n"
"x[3]: 0\n"
"x[4]: 10\n"
"x[5]: 55\n"
"x[5]: 55\n"
"x[6]: 66\n"
"it == it? yes\n"
"!(it != it)? yes\n"
"!(it < it)? yes\n"
"!(it > it)? yes\n"
"it <= it? yes\n"
"it >= it? yes\n"
"!(it == it_minus_1)? yes\n"
"it != it_minus_1? yes\n"
"!(it < it_minus_1)? yes\n"
"it > it_minus_1? yes\n"
"!(it <= it_minus_1)? yes\n"
"it >= it_minus_1? yes\n"
"!(it_minus_1 == it)? yes\n"
"it_minus_1 != it? yes\n"
"it_minus_1 < it? yes\n"
"!(it_minus_1 > it)? yes\n"
"it_minus_1 <= it? yes\n"
"!(it_minus_1 >= it)? yes\n"
"!(it == it_plus_1)? yes\n"
"it != it_plus_1? yes\n"
"it < it_plus_1? yes\n"
"!(it > it_plus_1)? yes\n"
"it <= it_plus_1? yes\n"
"!(it >= it_plus_1)? yes\n"
"!(it_plus_1 == it)? yes\n"
"it_plus_1 != it? yes\n"
"!(it_plus_1 < it)? yes\n"
"it_plus_1 > it? yes\n"
"!(it_plus_1 <= it)? yes\n"
"it_plus_1 >= it? yes\n"
"x[4]: 10\n"
"x[4]: 10\n"
"x[3]: 0\n"
"x[4]: 10\n"
"x[5]: 55\n"
"x[6]: 66\n"
"it == it? yes\n"
"!(it != it)? yes\n"
"!(it < it)? yes\n"
"!(it > it)? yes\n"
"it <= it? yes\n"
"it >= it? yes\n"
"!(it == it_minus_1)? yes\n"
"it != it_minus_1? yes\n"
"!(it < it_minus_1)? yes\n"
"it > it_minus_1? yes\n"
"!(it <= it_minus_1)? yes\n"
"it >= it_minus_1? yes\n"
"!(it_minus_1 == it)? yes\n"
"it_minus_1 != it? yes\n"
"it_minus_1 < it? yes\n"
"!(it_minus_1 > it)? yes\n"
"it_minus_1 <= it? yes\n"
"!(it_minus_1 >= it)? yes\n"
"!(it == it_plus_1)? yes\n"
"it != it_plus_1? yes\n"
"it < it_plus_1? yes\n"
"!(it > it_plus_1)? yes\n"
"it <= it_plus_1? yes\n"
"!(it >= it_plus_1)? yes\n"
"!(it_plus_1 == it)? yes\n"
"it_plus_1 != it? yes\n"
"!(it_plus_1 < it)? yes\n"
"it_plus_1 > it? yes\n"
"!(it_plus_1 <= it)? yes\n"
"it_plus_1 >= it? yes\n"
"x.begin() == x.begin() + 1 - 1? yes\n"
"x.begin() < x.end()? yes\n"
"z.begin() < z.end()? no\n"
"z.begin() <= z.end()? yes\n"
"z.begin() == z.end()? yes\n"
"x[??]: 10\n"
"x[??]: 55\n"
"x[??]: 66\n"
"y[??]: -12\n"
"y[??]: -47\n"
"y[??]: -48\n"
"y[??]: -49\n"
"y[??]: -49\n"
"y[??]: -48\n"
"y[??]: -47\n"
"y[??]: -12\n"
"y[??]: -49\n"
"y[??]: -48\n"
"y[??]: -47\n"
"y[??]: -12\n"
"first non-empty y: -12\n"
"first non-empty x: 10\n"
"first non-empty x: 10\n"
"first non-empty x: 10\n"
"first non-empty y: -12\n"
"first non-empty x: 10\n"
"first non-empty x: 10\n"
"first non-empty x: 10\n"
"x.begin() == x.begin() + 1 - 1? yes\n"
"z.begin() != z.end()? no\n"
"get_pos() for const nonempty_iterator: 0 == 0\n"
"get_pos() for const nonempty_iterator: 9 == 9\n"
"get_pos() for const nonempty_iterator: 18 == 18\n"
"get_pos() for const nonempty_iterator: 27 == 27\n"
"get_pos() for const nonempty_iterator: 36 == 36\n"
"get_pos() for const nonempty_iterator: 45 == 45\n"
"get_pos() for const nonempty_iterator: 54 == 54\n"
"get_pos() for const nonempty_iterator: 63 == 63\n"
"get_pos() for const nonempty_iterator: 72 == 72\n"
"get_pos() for const nonempty_iterator: 81 == 81\n"
"get_pos() for const nonempty_iterator: 90 == 90\n"
"get_pos() for const nonempty_iterator: 99 == 99\n"
"get_pos() for nonempty_iterator: 0 == 0\n"
"get_pos() for nonempty_iterator: 9 == 9\n"
"get_pos() for nonempty_iterator: 18 == 18\n"
"get_pos() for nonempty_iterator: 27 == 27\n"
"get_pos() for nonempty_iterator: 36 == 36\n"
"get_pos() for nonempty_iterator: 45 == 45\n"
"get_pos() for nonempty_iterator: 54 == 54\n"
"get_pos() for nonempty_iterator: 63 == 63\n"
"get_pos() for nonempty_iterator: 72 == 72\n"
"get_pos() for nonempty_iterator: 81 == 81\n"
"get_pos() for nonempty_iterator: 90 == 90\n"
"get_pos() for nonempty_iterator: 99 == 99\n"
"x has 3/7 buckets, y 4/70, z 0/0\n"
"y shrank and grew: it's now 2/70\n"
"y[12] = -12, y.get(12) = -12\n"
"y[12] cleared. y now 1/70. y[12] = 0, y.get(12) = 0\n"
"y == z? no\n"
"y[10] is set\n"
"y[11] is set\n"
"y[13] is set\n"
"y[14] is set\n"
"y[30] is set\n"
"y[31] is set\n"
"y[32] is set\n"
"y[33] is set\n"
"y[35] is set\n"
"y[36] is set\n"
"y[37] is set\n"
"y[9898] is set\n"
"That's 12 set buckets\n"
"Starting from y[32]...\n"
"y[??] = -32\n"
"y[??] = -33\n"
"y[??] = -35\n"
"y[??] = -36\n"
"y[??] = -37\n"
"y[??] = -9898\n"
"From y[32] down...\n"
"y[??] = -31\n"
"y[??] = -30\n"
"y[??] = -14\n"
"y[??] = -13\n"
"y[??] = -11\n"
"y[??] = -10\n"
"y2[10] is -10\n"
"y2[11] is -11\n"
"y2[13] is -13\n"
"y2[14] is -14\n"
"y2[30] is -30\n"
"y2[31] is -31\n"
"y2[32] is -32\n"
"y2[33] is -33\n"
"y2[35] is -35\n"
"y2[36] is -36\n"
"y2[37] is -37\n"
"y2[9898] is -9898\n"
"That's 12 set buckets\n"
"y2[10] is -10\n"
"y2[11] is -11\n"
"y2[13] is -13\n"
"y2[14] is -14\n"
"y2[30] is -30\n"
"y2[31] is -31\n"
"y2[32] is -32\n"
"y2[33] is -33\n"
"y2[35] is -35\n"
"y2[36] is -36\n"
"y2[37] is -37\n"
"y2[9898] is -9898\n"
"That's 12 set buckets\n"
"string test\n"
"x[0]: \n"
"x[1]: \n"
"x[2]: \n"
"x[3]: \n"
"x[4]: foo\n"
"x[5]: \n"
"x[6]: \n"
"x.begin() == x.begin() + 1 - 1? yes\n"
"x.begin() < x.end()? yes\n"
"z.begin() < z.end()? no\n"
"z.begin() <= z.end()? yes\n"
"z.begin() == z.end()? yes\n"
"x[??]: foo\n"
"y[??]: orange\n"
"y[??]: grape\n"
"y[??]: pear\n"
"y[??]: apple\n"
"x has 1/7 buckets, y 4/70, z 0/0\n"
"y shrank and grew: it's now 2/70\n"
"y[12] = orange, y.get(12) = orange\n"
"y[12] cleared. y now 1/70. y[12] = , y.get(12) = \n"
"y == z? no\n"
"y[10] is set\n"
"y[11] is set\n"
"y[13] is set\n"
"y[14] is set\n"
"y[30] is set\n"
"y[31] is set\n"
"y[32] is set\n"
"y[33] is set\n"
"y[35] is set\n"
"y[36] is set\n"
"y[37] is set\n"
"y[9898] is set\n"
"That's 12 set buckets\n"
"Starting from y[32]...\n"
"y[??] = -32\n"
"y[??] = -33\n"
"y[??] = -35\n"
"y[??] = -36\n"
"y[??] = -37\n"
"y[??] = -9898\n"
"From y[32] down...\n"
"y[??] = -31\n"
"y[??] = -30\n"
"y[??] = -14\n"
"y[??] = -13\n"
"y[??] = -11\n"
"y[??] = -10\n"
"allocator test\n"
"sum_allocate_bytes > 0? yes\n"
"sum_allocate_bytes >= 10000 * sizeof(int)? yes\n"
"sum_deallocate_bytes >= 10000 * sizeof(int)? yes\n"
"sum_allocate_bytes >= 2000 * sizeof(int)? yes\n"
"sum_deallocate_bytes >= 1000 * sizeof(int)? yes\n"
"sum_deallocate_bytes < 1000 * sizeof(int)? yes\n"
"sum_deallocate_bytes >= 1000 * sizeof(int)? yes\n"
"x.num_nonempty() == 0? yes\n"
"y[0]: 1\n"
"y[39999]: 40000\n"
"u.num_nonempty() == 0? yes\n"
"v[0]: 1\n"
"v[39999]: 40000\n"
"a.num_nonempty() == 0? yes\n"
"b[0]: aa\n"
"b[39999]: aa\n"
);
// defined at bottom of file for ease of maintainence
int main(int argc, char **argv) { // though we ignore the args
(void)argc;
(void)argv;
TestInt();
TestString();
TestAllocator();
// Finally, check to see if our output (in out) is what it's supposed to be.
const size_t r = sizeof(g_expected) - 1;
if ( r != static_cast<size_t>(out - outbuf) || // output not the same size
memcmp(outbuf, g_expected, r) ) { // or bytes differed
fprintf(stderr, "TESTS FAILED\n\nEXPECTED:\n\n%s\n\nACTUAL:\n\n%s\n\n",
g_expected, outbuf);
return 1;
} else {
printf("PASS.\n");
return 0;
}
}

View file

@ -0,0 +1,134 @@
// Copyright 2005 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ----
//
// These tests are really compile time tests.
// If you try to step through this in a debugger
// you will not see any evaluations, merely that
// value is assigned true or false sequentially.
#include <sparsehash/internal/sparseconfig.h>
#include <config.h>
#include <sparsehash/template_util.h>
#include "testutil.h"
using namespace GOOGLE_NAMESPACE;
namespace {
TEST(TemplateUtilTest, TestSize) {
EXPECT_GT(sizeof(GOOGLE_NAMESPACE::big_), sizeof(GOOGLE_NAMESPACE::small_));
}
TEST(TemplateUtilTest, TestIntegralConstants) {
// test the built-in types.
EXPECT_TRUE(true_type::value);
EXPECT_FALSE(false_type::value);
typedef integral_constant<int, 1> one_type;
EXPECT_EQ(1, one_type::value);
}
TEST(TemplateUtilTest, TestTemplateIf) {
typedef if_<true, true_type, false_type>::type if_true;
EXPECT_TRUE(if_true::value);
typedef if_<false, true_type, false_type>::type if_false;
EXPECT_FALSE(if_false::value);
}
TEST(TemplateUtilTest, TestTemplateTypeEquals) {
// Check that the TemplateTypeEquals works correctly.
bool value = false;
// Test the same type is true.
value = type_equals_<int, int>::value;
EXPECT_TRUE(value);
// Test different types are false.
value = type_equals_<float, int>::value;
EXPECT_FALSE(value);
// Test type aliasing.
typedef const int foo;
value = type_equals_<const foo, const int>::value;
EXPECT_TRUE(value);
}
TEST(TemplateUtilTest, TestTemplateAndOr) {
// Check that the TemplateTypeEquals works correctly.
bool value = false;
// Yes && Yes == true.
value = and_<true_, true_>::value;
EXPECT_TRUE(value);
// Yes && No == false.
value = and_<true_, false_>::value;
EXPECT_FALSE(value);
// No && Yes == false.
value = and_<false_, true_>::value;
EXPECT_FALSE(value);
// No && No == false.
value = and_<false_, false_>::value;
EXPECT_FALSE(value);
// Yes || Yes == true.
value = or_<true_, true_>::value;
EXPECT_TRUE(value);
// Yes || No == true.
value = or_<true_, false_>::value;
EXPECT_TRUE(value);
// No || Yes == true.
value = or_<false_, true_>::value;
EXPECT_TRUE(value);
// No || No == false.
value = or_<false_, false_>::value;
EXPECT_FALSE(value);
}
TEST(TemplateUtilTest, TestIdentity) {
EXPECT_TRUE(
(type_equals_<GOOGLE_NAMESPACE::identity_<int>::type, int>::value));
EXPECT_TRUE(
(type_equals_<GOOGLE_NAMESPACE::identity_<void>::type, void>::value));
}
} // namespace
#include <iostream>
int main(int, char **) {
// All the work is done in the static constructors. If they don't
// die, the tests have all passed.
std::cout << "PASS\n";
return 0;
}

View file

@ -0,0 +1,266 @@
// Copyright (c) 2010, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
// This macro mimics a unittest framework, but is a bit less flexible
// than most. It requires a superclass to derive from, and does all
// work in global constructors. The tricky part is implementing
// TYPED_TEST.
#ifndef SPARSEHASH_TEST_UTIL_H_
#define SPARSEHASH_TEST_UTIL_H_
#include <sparsehash/internal/sparseconfig.h>
#include "config.h"
#include <stdio.h>
#include <stdlib.h> // for exit
#include <stdexcept> // for length_error
_START_GOOGLE_NAMESPACE_
namespace testing {
#define EXPECT_TRUE(cond) do { \
if (!(cond)) { \
::fputs("Test failed: " #cond "\n", stderr); \
::exit(1); \
} \
} while (0)
#define EXPECT_FALSE(a) EXPECT_TRUE(!(a))
#define EXPECT_EQ(a, b) EXPECT_TRUE((a) == (b))
#define EXPECT_NE(a, b) EXPECT_TRUE((a) != (b))
#define EXPECT_LT(a, b) EXPECT_TRUE((a) < (b))
#define EXPECT_GT(a, b) EXPECT_TRUE((a) > (b))
#define EXPECT_LE(a, b) EXPECT_TRUE((a) <= (b))
#define EXPECT_GE(a, b) EXPECT_TRUE((a) >= (b))
#define EXPECT_DEATH(cmd, expected_error_string) \
try { \
cmd; \
EXPECT_FALSE("did not see expected error: " #expected_error_string); \
} catch (const std::length_error&) { \
/* Good, the cmd failed. */ \
}
#define TEST(suitename, testname) \
class TEST_##suitename##_##testname { \
public: \
TEST_##suitename##_##testname() { \
::fputs("Running " #suitename "." #testname "\n", stderr); \
Run(); \
} \
void Run(); \
}; \
static TEST_##suitename##_##testname \
test_instance_##suitename##_##testname; \
void TEST_##suitename##_##testname::Run()
template<typename C1, typename C2, typename C3, typename C4, typename C5,
typename C6> struct TypeList6 {
typedef C1 type1;
typedef C2 type2;
typedef C3 type3;
typedef C4 type4;
typedef C5 type5;
typedef C6 type6;
};
// I need to list 18 types here, for code below to compile, though
// only the first 6 are ever used.
#define TYPED_TEST_CASE_6(classname, typelist) \
typedef typelist::type1 classname##_type1; \
typedef typelist::type2 classname##_type2; \
typedef typelist::type3 classname##_type3; \
typedef typelist::type4 classname##_type4; \
typedef typelist::type5 classname##_type5; \
typedef typelist::type6 classname##_type6; \
static const int classname##_numtypes = 6; \
typedef typelist::type1 classname##_type7; \
typedef typelist::type1 classname##_type8; \
typedef typelist::type1 classname##_type9; \
typedef typelist::type1 classname##_type10; \
typedef typelist::type1 classname##_type11; \
typedef typelist::type1 classname##_type12; \
typedef typelist::type1 classname##_type13; \
typedef typelist::type1 classname##_type14; \
typedef typelist::type1 classname##_type15; \
typedef typelist::type1 classname##_type16; \
typedef typelist::type1 classname##_type17; \
typedef typelist::type1 classname##_type18;
template<typename C1, typename C2, typename C3, typename C4, typename C5,
typename C6, typename C7, typename C8, typename C9, typename C10,
typename C11, typename C12, typename C13, typename C14, typename C15,
typename C16, typename C17, typename C18> struct TypeList18 {
typedef C1 type1;
typedef C2 type2;
typedef C3 type3;
typedef C4 type4;
typedef C5 type5;
typedef C6 type6;
typedef C7 type7;
typedef C8 type8;
typedef C9 type9;
typedef C10 type10;
typedef C11 type11;
typedef C12 type12;
typedef C13 type13;
typedef C14 type14;
typedef C15 type15;
typedef C16 type16;
typedef C17 type17;
typedef C18 type18;
};
#define TYPED_TEST_CASE_18(classname, typelist) \
typedef typelist::type1 classname##_type1; \
typedef typelist::type2 classname##_type2; \
typedef typelist::type3 classname##_type3; \
typedef typelist::type4 classname##_type4; \
typedef typelist::type5 classname##_type5; \
typedef typelist::type6 classname##_type6; \
typedef typelist::type7 classname##_type7; \
typedef typelist::type8 classname##_type8; \
typedef typelist::type9 classname##_type9; \
typedef typelist::type10 classname##_type10; \
typedef typelist::type11 classname##_type11; \
typedef typelist::type12 classname##_type12; \
typedef typelist::type13 classname##_type13; \
typedef typelist::type14 classname##_type14; \
typedef typelist::type15 classname##_type15; \
typedef typelist::type16 classname##_type16; \
typedef typelist::type17 classname##_type17; \
typedef typelist::type18 classname##_type18; \
static const int classname##_numtypes = 18;
#define TYPED_TEST(superclass, testname) \
template<typename TypeParam> \
class TEST_onetype_##superclass##_##testname : \
public superclass<TypeParam> { \
public: \
TEST_onetype_##superclass##_##testname() { \
Run(); \
} \
private: \
void Run(); \
}; \
class TEST_typed_##superclass##_##testname { \
public: \
explicit TEST_typed_##superclass##_##testname() { \
if (superclass##_numtypes >= 1) { \
::fputs("Running " #superclass "." #testname ".1\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type1> t; \
} \
if (superclass##_numtypes >= 2) { \
::fputs("Running " #superclass "." #testname ".2\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type2> t; \
} \
if (superclass##_numtypes >= 3) { \
::fputs("Running " #superclass "." #testname ".3\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type3> t; \
} \
if (superclass##_numtypes >= 4) { \
::fputs("Running " #superclass "." #testname ".4\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type4> t; \
} \
if (superclass##_numtypes >= 5) { \
::fputs("Running " #superclass "." #testname ".5\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type5> t; \
} \
if (superclass##_numtypes >= 6) { \
::fputs("Running " #superclass "." #testname ".6\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type6> t; \
} \
if (superclass##_numtypes >= 7) { \
::fputs("Running " #superclass "." #testname ".7\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type7> t; \
} \
if (superclass##_numtypes >= 8) { \
::fputs("Running " #superclass "." #testname ".8\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type8> t; \
} \
if (superclass##_numtypes >= 9) { \
::fputs("Running " #superclass "." #testname ".9\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type9> t; \
} \
if (superclass##_numtypes >= 10) { \
::fputs("Running " #superclass "." #testname ".10\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type10> t; \
} \
if (superclass##_numtypes >= 11) { \
::fputs("Running " #superclass "." #testname ".11\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type11> t; \
} \
if (superclass##_numtypes >= 12) { \
::fputs("Running " #superclass "." #testname ".12\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type12> t; \
} \
if (superclass##_numtypes >= 13) { \
::fputs("Running " #superclass "." #testname ".13\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type13> t; \
} \
if (superclass##_numtypes >= 14) { \
::fputs("Running " #superclass "." #testname ".14\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type14> t; \
} \
if (superclass##_numtypes >= 15) { \
::fputs("Running " #superclass "." #testname ".15\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type15> t; \
} \
if (superclass##_numtypes >= 16) { \
::fputs("Running " #superclass "." #testname ".16\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type16> t; \
} \
if (superclass##_numtypes >= 17) { \
::fputs("Running " #superclass "." #testname ".17\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type17> t; \
} \
if (superclass##_numtypes >= 18) { \
::fputs("Running " #superclass "." #testname ".18\n", stderr); \
TEST_onetype_##superclass##_##testname<superclass##_type18> t; \
} \
} \
}; \
static TEST_typed_##superclass##_##testname \
test_instance_typed_##superclass##_##testname; \
template<class TypeParam> \
void TEST_onetype_##superclass##_##testname<TypeParam>::Run()
// This is a dummy class just to make converting from internal-google
// to opensourcing easier.
class Test { };
} // namespace testing
_END_GOOGLE_NAMESPACE_
#endif // SPARSEHASH_TEST_UTIL_H_

View file

@ -0,0 +1,729 @@
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
// Authors: Sanjay Ghemawat and Craig Silverstein
// Time various hash map implementations
//
// Below, times are per-call. "Memory use" is "bytes in use by
// application" as reported by tcmalloc, compared before and after the
// function call. This does not really report fragmentation, which is
// not bad for the sparse* routines but bad for the dense* ones.
//
// The tests generally yield best-case performance because the
// code uses sequential keys; on the other hand, "map_fetch_random" does
// lookups in a pseudorandom order. Also, "stresshashfunction" is
// a stress test of sorts. It uses keys from an arithmetic sequence, which,
// if combined with a quick-and-dirty hash function, will yield worse
// performance than the otherwise similar "map_predict/grow."
//
// Consider doing the following to get good numbers:
//
// 1. Run the tests on a machine with no X service. Make sure no other
// processes are running.
// 2. Minimize compiled-code differences. Compare results from the same
// binary, if possible, instead of comparing results from two different
// binaries.
//
// See PERFORMANCE for the output of one example run.
#include <sparsehash/internal/sparseconfig.h>
#include <config.h>
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif // for uintptr_t
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern "C" {
#include <time.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
#ifdef HAVE_SYS_UTSNAME_H
# include <sys/utsname.h>
#endif // for uname()
}
// The functions that we call on each map, that differ for different types.
// By default each is a noop, but we redefine them for types that need them.
#include <map>
#include HASH_MAP_H
#include <algorithm>
#include <vector>
#include <sparsehash/type_traits.h>
#include <sparsehash/dense_hash_map>
#include <sparsehash/sparse_hash_map>
using std::map;
using std::swap;
using std::vector;
using GOOGLE_NAMESPACE::dense_hash_map;
using GOOGLE_NAMESPACE::sparse_hash_map;
static bool FLAGS_test_sparse_hash_map = true;
static bool FLAGS_test_dense_hash_map = true;
static bool FLAGS_test_hash_map = true;
static bool FLAGS_test_map = true;
static bool FLAGS_test_4_bytes = true;
static bool FLAGS_test_8_bytes = true;
static bool FLAGS_test_16_bytes = true;
static bool FLAGS_test_256_bytes = true;
#if defined(HAVE_UNORDERED_MAP)
using HASH_NAMESPACE::unordered_map;
#elif defined(HAVE_HASH_MAP) || defined(_MSC_VER)
using HASH_NAMESPACE::hash_map;
#endif
static const int kDefaultIters = 10000000;
// A version of each of the hashtable classes we test, that has been
// augumented to provide a common interface. For instance, the
// sparse_hash_map and dense_hash_map versions set empty-key and
// deleted-key (we can do this because all our tests use int-like
// keys), so the users don't have to. The hash_map version adds
// resize(), so users can just call resize() for all tests without
// worrying about whether the map-type supports it or not.
template<typename K, typename V, typename H>
class EasyUseSparseHashMap : public sparse_hash_map<K,V,H> {
public:
EasyUseSparseHashMap() {
this->set_deleted_key(-1);
}
};
template<typename K, typename V, typename H>
class EasyUseDenseHashMap : public dense_hash_map<K,V,H> {
public:
EasyUseDenseHashMap() {
this->set_empty_key(-1);
this->set_deleted_key(-2);
}
};
// For pointers, we only set the empty key.
template<typename K, typename V, typename H>
class EasyUseSparseHashMap<K*, V, H> : public sparse_hash_map<K*,V,H> {
public:
EasyUseSparseHashMap() { }
};
template<typename K, typename V, typename H>
class EasyUseDenseHashMap<K*, V, H> : public dense_hash_map<K*,V,H> {
public:
EasyUseDenseHashMap() {
this->set_empty_key((K*)(~0));
}
};
#if defined(HAVE_UNORDERED_MAP)
template<typename K, typename V, typename H>
class EasyUseHashMap : public unordered_map<K,V,H> {
public:
// resize() is called rehash() in tr1
void resize(size_t r) { this->rehash(r); }
};
#elif defined(_MSC_VER)
template<typename K, typename V, typename H>
class EasyUseHashMap : public hash_map<K,V,H> {
public:
void resize(size_t r) { }
};
#elif defined(HAVE_HASH_MAP)
template<typename K, typename V, typename H>
class EasyUseHashMap : public hash_map<K,V,H> {
public:
// Don't need to do anything: hash_map is already easy to use!
};
#endif
template<typename K, typename V>
class EasyUseMap : public map<K,V> {
public:
void resize(size_t) { } // map<> doesn't support resize
};
// Returns the number of hashes that have been done since the last
// call to NumHashesSinceLastCall(). This is shared across all
// HashObject instances, which isn't super-OO, but avoids two issues:
// (1) making HashObject bigger than it ought to be (this is very
// important for our testing), and (2) having to pass around
// HashObject objects everywhere, which is annoying.
static int g_num_hashes;
static int g_num_copies;
int NumHashesSinceLastCall() {
int retval = g_num_hashes;
g_num_hashes = 0;
return retval;
}
int NumCopiesSinceLastCall() {
int retval = g_num_copies;
g_num_copies = 0;
return retval;
}
/*
* These are the objects we hash. Size is the size of the object
* (must be > sizeof(int). Hashsize is how many of these bytes we
* use when hashing (must be > sizeof(int) and < Size).
*/
template<int Size, int Hashsize> class HashObject {
public:
typedef HashObject<Size, Hashsize> class_type;
HashObject() {}
HashObject(int i) : i_(i) {
memset(buffer_, i & 255, sizeof(buffer_)); // a "random" char
}
HashObject(const HashObject& that) {
operator=(that);
}
void operator=(const HashObject& that) {
g_num_copies++;
this->i_ = that.i_;
memcpy(this->buffer_, that.buffer_, sizeof(this->buffer_));
}
size_t Hash() const {
g_num_hashes++;
int hashval = i_;
for (size_t i = 0; i < Hashsize - sizeof(i_); ++i) {
hashval += buffer_[i];
}
return SPARSEHASH_HASH<int>()(hashval);
}
bool operator==(const class_type& that) const { return this->i_ == that.i_; }
bool operator< (const class_type& that) const { return this->i_ < that.i_; }
bool operator<=(const class_type& that) const { return this->i_ <= that.i_; }
private:
int i_; // the key used for hashing
char buffer_[Size - sizeof(int)];
};
// A specialization for the case sizeof(buffer_) == 0
template<> class HashObject<sizeof(int), sizeof(int)> {
public:
typedef HashObject<sizeof(int), sizeof(int)> class_type;
HashObject() {}
HashObject(int i) : i_(i) {}
HashObject(const HashObject& that) {
operator=(that);
}
void operator=(const HashObject& that) {
g_num_copies++;
this->i_ = that.i_;
}
size_t Hash() const {
g_num_hashes++;
return SPARSEHASH_HASH<int>()(i_);
}
bool operator==(const class_type& that) const { return this->i_ == that.i_; }
bool operator< (const class_type& that) const { return this->i_ < that.i_; }
bool operator<=(const class_type& that) const { return this->i_ <= that.i_; }
private:
int i_; // the key used for hashing
};
_START_GOOGLE_NAMESPACE_
// Let the hashtable implementations know it can use an optimized memcpy,
// because the compiler defines both the destructor and copy constructor.
template<int Size, int Hashsize>
struct has_trivial_copy< HashObject<Size, Hashsize> > : true_type { };
template<int Size, int Hashsize>
struct has_trivial_destructor< HashObject<Size, Hashsize> > : true_type { };
_END_GOOGLE_NAMESPACE_
class HashFn {
public:
template<int Size, int Hashsize>
size_t operator()(const HashObject<Size,Hashsize>& obj) const {
return obj.Hash();
}
// Do the identity hash for pointers.
template<int Size, int Hashsize>
size_t operator()(const HashObject<Size,Hashsize>* obj) const {
return reinterpret_cast<uintptr_t>(obj);
}
// Less operator for MSVC's hash containers.
template<int Size, int Hashsize>
bool operator()(const HashObject<Size,Hashsize>& a,
const HashObject<Size,Hashsize>& b) const {
return a < b;
}
template<int Size, int Hashsize>
bool operator()(const HashObject<Size,Hashsize>* a,
const HashObject<Size,Hashsize>* b) const {
return a < b;
}
// These two public members are required by msvc. 4 and 8 are defaults.
static const size_t bucket_size = 4;
static const size_t min_buckets = 8;
};
/*
* Measure resource usage.
*/
class Rusage {
public:
/* Start collecting usage */
Rusage() { Reset(); }
/* Reset collection */
void Reset();
/* Show usage, in seconds */
double UserTime();
private:
#if defined HAVE_SYS_RESOURCE_H
struct rusage start;
#elif defined HAVE_WINDOWS_H
long long int start;
#else
time_t start_time_t;
#endif
};
inline void Rusage::Reset() {
g_num_copies = 0;
g_num_hashes = 0;
#if defined HAVE_SYS_RESOURCE_H
getrusage(RUSAGE_SELF, &start);
#elif defined HAVE_WINDOWS_H
start = GetTickCount();
#else
time(&start_time_t);
#endif
}
inline double Rusage::UserTime() {
#if defined HAVE_SYS_RESOURCE_H
struct rusage u;
getrusage(RUSAGE_SELF, &u);
struct timeval result;
result.tv_sec = u.ru_utime.tv_sec - start.ru_utime.tv_sec;
result.tv_usec = u.ru_utime.tv_usec - start.ru_utime.tv_usec;
return double(result.tv_sec) + double(result.tv_usec) / 1000000.0;
#elif defined HAVE_WINDOWS_H
return double(GetTickCount() - start) / 1000.0;
#else
time_t now;
time(&now);
return now - start_time_t;
#endif
}
static void print_uname() {
#ifdef HAVE_SYS_UTSNAME_H
struct utsname u;
if (uname(&u) == 0) {
printf("%s %s %s %s %s\n",
u.sysname, u.nodename, u.release, u.version, u.machine);
}
#endif
}
// Generate stamp for this run
static void stamp_run(int iters) {
time_t now = time(0);
printf("======\n");
fflush(stdout);
print_uname();
printf("Average over %d iterations\n", iters);
fflush(stdout);
// don't need asctime_r/gmtime_r: we're not threaded
printf("Current time (GMT): %s", asctime(gmtime(&now)));
}
// This depends on the malloc implementation for exactly what it does
// -- and thus requires work after the fact to make sense of the
// numbers -- and also is likely thrown off by the memory management
// STL tries to do on its own.
#ifdef HAVE_GOOGLE_MALLOC_EXTENSION_H
#include <google/malloc_extension.h>
static size_t CurrentMemoryUsage() {
size_t result;
if (MallocExtension::instance()->GetNumericProperty(
"generic.current_allocated_bytes",
&result)) {
return result;
} else {
return 0;
}
}
#else /* not HAVE_GOOGLE_MALLOC_EXTENSION_H */
static size_t CurrentMemoryUsage() { return 0; }
#endif
static void report(char const* title, double t,
int iters,
size_t start_memory, size_t end_memory) {
// Construct heap growth report text if applicable
char heap[100] = "";
if (end_memory > start_memory) {
snprintf(heap, sizeof(heap), "%7.1f MB",
(end_memory - start_memory) / 1048576.0);
}
printf("%-20s %6.1f ns (%8d hashes, %8d copies)%s\n",
title, (t * 1000000000.0 / iters),
NumHashesSinceLastCall(), NumCopiesSinceLastCall(),
heap);
fflush(stdout);
}
template<class MapType>
static void time_map_grow(int iters) {
MapType set;
Rusage t;
const size_t start = CurrentMemoryUsage();
t.Reset();
for (int i = 0; i < iters; i++) {
set[i] = i+1;
}
double ut = t.UserTime();
const size_t finish = CurrentMemoryUsage();
report("map_grow", ut, iters, start, finish);
}
template<class MapType>
static void time_map_grow_predicted(int iters) {
MapType set;
Rusage t;
const size_t start = CurrentMemoryUsage();
set.resize(iters);
t.Reset();
for (int i = 0; i < iters; i++) {
set[i] = i+1;
}
double ut = t.UserTime();
const size_t finish = CurrentMemoryUsage();
report("map_predict/grow", ut, iters, start, finish);
}
template<class MapType>
static void time_map_replace(int iters) {
MapType set;
Rusage t;
int i;
for (i = 0; i < iters; i++) {
set[i] = i+1;
}
t.Reset();
for (i = 0; i < iters; i++) {
set[i] = i+1;
}
double ut = t.UserTime();
report("map_replace", ut, iters, 0, 0);
}
template<class MapType>
static void time_map_fetch(int iters, const vector<int>& indices,
char const* title) {
MapType set;
Rusage t;
int r;
int i;
for (i = 0; i < iters; i++) {
set[i] = i+1;
}
r = 1;
t.Reset();
for (i = 0; i < iters; i++) {
r ^= static_cast<int>(set.find(indices[i]) != set.end());
}
double ut = t.UserTime();
srand(r); // keep compiler from optimizing away r (we never call rand())
report(title, ut, iters, 0, 0);
}
template<class MapType>
static void time_map_fetch_sequential(int iters) {
vector<int> v(iters);
for (int i = 0; i < iters; i++) {
v[i] = i;
}
time_map_fetch<MapType>(iters, v, "map_fetch_sequential");
}
// Apply a pseudorandom permutation to the given vector.
static void shuffle(vector<int>* v) {
srand(9);
for (int n = v->size(); n >= 2; n--) {
swap((*v)[n - 1], (*v)[static_cast<unsigned>(rand()) % n]);
}
}
template<class MapType>
static void time_map_fetch_random(int iters) {
vector<int> v(iters);
for (int i = 0; i < iters; i++) {
v[i] = i;
}
shuffle(&v);
time_map_fetch<MapType>(iters, v, "map_fetch_random");
}
template<class MapType>
static void time_map_fetch_empty(int iters) {
MapType set;
Rusage t;
int r;
int i;
r = 1;
t.Reset();
for (i = 0; i < iters; i++) {
r ^= static_cast<int>(set.find(i) != set.end());
}
double ut = t.UserTime();
srand(r); // keep compiler from optimizing away r (we never call rand())
report("map_fetch_empty", ut, iters, 0, 0);
}
template<class MapType>
static void time_map_remove(int iters) {
MapType set;
Rusage t;
int i;
for (i = 0; i < iters; i++) {
set[i] = i+1;
}
t.Reset();
for (i = 0; i < iters; i++) {
set.erase(i);
}
double ut = t.UserTime();
report("map_remove", ut, iters, 0, 0);
}
template<class MapType>
static void time_map_toggle(int iters) {
MapType set;
Rusage t;
int i;
const size_t start = CurrentMemoryUsage();
t.Reset();
for (i = 0; i < iters; i++) {
set[i] = i+1;
set.erase(i);
}
double ut = t.UserTime();
const size_t finish = CurrentMemoryUsage();
report("map_toggle", ut, iters, start, finish);
}
template<class MapType>
static void time_map_iterate(int iters) {
MapType set;
Rusage t;
int r;
int i;
for (i = 0; i < iters; i++) {
set[i] = i+1;
}
r = 1;
t.Reset();
for (typename MapType::const_iterator it = set.begin(), it_end = set.end();
it != it_end;
++it) {
r ^= it->second;
}
double ut = t.UserTime();
srand(r); // keep compiler from optimizing away r (we never call rand())
report("map_iterate", ut, iters, 0, 0);
}
template<class MapType>
static void stresshashfunction(int desired_insertions,
int map_size,
int stride) {
Rusage t;
int num_insertions = 0;
// One measurement of user time (in seconds) is done for each iteration of
// the outer loop. The times are summed.
double total_seconds = 0;
const int k = desired_insertions / map_size;
MapType set;
for (int o = 0; o < k; o++) {
set.clear();
set.resize(map_size);
t.Reset();
const int maxint = (1ull << (sizeof(int) * 8 - 1)) - 1;
// Use n arithmetic sequences. Using just one may lead to overflow
// if stride * map_size > maxint. Compute n by requiring
// stride * map_size/n < maxint, i.e., map_size/(maxint/stride) < n
char* key; // something we can do math on
const int n = map_size / (maxint / stride) + 1;
for (int i = 0; i < n; i++) {
key = NULL;
key += i;
for (int j = 0; j < map_size/n; j++) {
key += stride;
set[reinterpret_cast<typename MapType::key_type>(key)]
= ++num_insertions;
}
}
total_seconds += t.UserTime();
}
printf("stresshashfunction map_size=%d stride=%d: %.1fns/insertion\n",
map_size, stride, total_seconds * 1e9 / num_insertions);
}
template<class MapType>
static void stresshashfunction(int num_inserts) {
static const int kMapSizes[] = {256, 1024};
for (unsigned i = 0; i < sizeof(kMapSizes) / sizeof(kMapSizes[0]); i++) {
const int map_size = kMapSizes[i];
for (int stride = 1; stride <= map_size; stride *= map_size) {
stresshashfunction<MapType>(num_inserts, map_size, stride);
}
}
}
template<class MapType, class StressMapType>
static void measure_map(const char* label, int obj_size, int iters,
bool stress_hash_function) {
printf("\n%s (%d byte objects, %d iterations):\n", label, obj_size, iters);
if (1) time_map_grow<MapType>(iters);
if (1) time_map_grow_predicted<MapType>(iters);
if (1) time_map_replace<MapType>(iters);
if (1) time_map_fetch_random<MapType>(iters);
if (1) time_map_fetch_sequential<MapType>(iters);
if (1) time_map_fetch_empty<MapType>(iters);
if (1) time_map_remove<MapType>(iters);
if (1) time_map_toggle<MapType>(iters);
if (1) time_map_iterate<MapType>(iters);
// This last test is useful only if the map type uses hashing.
// And it's slow, so use fewer iterations.
if (stress_hash_function) {
// Blank line in the output makes clear that what follows isn't part of the
// table of results that we just printed.
puts("");
stresshashfunction<StressMapType>(iters / 4);
}
}
template<class ObjType>
static void test_all_maps(int obj_size, int iters) {
const bool stress_hash_function = obj_size <= 8;
if (FLAGS_test_sparse_hash_map)
measure_map< EasyUseSparseHashMap<ObjType, int, HashFn>,
EasyUseSparseHashMap<ObjType*, int, HashFn> >(
"SPARSE_HASH_MAP", obj_size, iters, stress_hash_function);
if (FLAGS_test_dense_hash_map)
measure_map< EasyUseDenseHashMap<ObjType, int, HashFn>,
EasyUseDenseHashMap<ObjType*, int, HashFn> >(
"DENSE_HASH_MAP", obj_size, iters, stress_hash_function);
if (FLAGS_test_hash_map)
measure_map< EasyUseHashMap<ObjType, int, HashFn>,
EasyUseHashMap<ObjType*, int, HashFn> >(
"STANDARD HASH_MAP", obj_size, iters, stress_hash_function);
if (FLAGS_test_map)
measure_map< EasyUseMap<ObjType, int>,
EasyUseMap<ObjType*, int> >(
"STANDARD MAP", obj_size, iters, false);
}
int main(int argc, char** argv) {
int iters = kDefaultIters;
if (argc > 1) { // first arg is # of iterations
iters = atoi(argv[1]);
}
stamp_run(iters);
#ifndef HAVE_SYS_RESOURCE_H
printf("\n*** WARNING ***: sys/resources.h was not found, so all times\n"
" reported are wall-clock time, not user time\n");
#endif
// It would be nice to set these at run-time, but by setting them at
// compile-time, we allow optimizations that make it as fast to use
// a HashObject as it would be to use just a straight int/char
// buffer. To keep memory use similar, we normalize the number of
// iterations based on size.
if (FLAGS_test_4_bytes) test_all_maps< HashObject<4,4> >(4, iters/1);
if (FLAGS_test_8_bytes) test_all_maps< HashObject<8,8> >(8, iters/2);
if (FLAGS_test_16_bytes) test_all_maps< HashObject<16,16> >(16, iters/4);
if (FLAGS_test_256_bytes) test_all_maps< HashObject<256,32> >(256, iters/32);
return 0;
}

View file

@ -0,0 +1,636 @@
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ----
#include <sparsehash/internal/sparseconfig.h>
#include <config.h>
#include <sparsehash/type_traits.h>
#include <stdlib.h> // for exit()
#include <stdio.h>
#include <string>
#include <vector>
#include "testutil.h"
typedef int int32;
typedef long int64;
using std::string;
using std::vector;
using std::pair;
using GOOGLE_NAMESPACE::add_reference;
using GOOGLE_NAMESPACE::has_trivial_assign;
using GOOGLE_NAMESPACE::has_trivial_constructor;
using GOOGLE_NAMESPACE::has_trivial_copy;
using GOOGLE_NAMESPACE::has_trivial_destructor;
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
using GOOGLE_NAMESPACE::is_convertible;
using GOOGLE_NAMESPACE::is_enum;
#endif
using GOOGLE_NAMESPACE::is_floating_point;
using GOOGLE_NAMESPACE::is_integral;
using GOOGLE_NAMESPACE::is_pointer;
using GOOGLE_NAMESPACE::is_pod;
using GOOGLE_NAMESPACE::is_reference;
using GOOGLE_NAMESPACE::is_same;
using GOOGLE_NAMESPACE::remove_const;
using GOOGLE_NAMESPACE::remove_cv;
using GOOGLE_NAMESPACE::remove_pointer;
using GOOGLE_NAMESPACE::remove_reference;
using GOOGLE_NAMESPACE::remove_volatile;
// This assertion produces errors like "error: invalid use of
// incomplete type 'struct <unnamed>::AssertTypesEq<const int, int>'"
// when it fails.
template<typename T, typename U> struct AssertTypesEq;
template<typename T> struct AssertTypesEq<T, T> {};
#define COMPILE_ASSERT_TYPES_EQ(T, U) static_cast<void>(AssertTypesEq<T, U>())
// A user-defined POD type.
struct A {
int n_;
};
// A user-defined non-POD type with a trivial copy constructor.
class B {
public:
explicit B(int n) : n_(n) { }
private:
int n_;
};
// Another user-defined non-POD type with a trivial copy constructor.
// We will explicitly declare C to have a trivial copy constructor
// by specializing has_trivial_copy.
class C {
public:
explicit C(int n) : n_(n) { }
private:
int n_;
};
_START_GOOGLE_NAMESPACE_
template<> struct has_trivial_copy<C> : true_type { };
_END_GOOGLE_NAMESPACE_
// Another user-defined non-POD type with a trivial assignment operator.
// We will explicitly declare C to have a trivial assignment operator
// by specializing has_trivial_assign.
class D {
public:
explicit D(int n) : n_(n) { }
private:
int n_;
};
_START_GOOGLE_NAMESPACE_
template<> struct has_trivial_assign<D> : true_type { };
_END_GOOGLE_NAMESPACE_
// Another user-defined non-POD type with a trivial constructor.
// We will explicitly declare E to have a trivial constructor
// by specializing has_trivial_constructor.
class E {
public:
int n_;
};
_START_GOOGLE_NAMESPACE_
template<> struct has_trivial_constructor<E> : true_type { };
_END_GOOGLE_NAMESPACE_
// Another user-defined non-POD type with a trivial destructor.
// We will explicitly declare E to have a trivial destructor
// by specializing has_trivial_destructor.
class F {
public:
explicit F(int n) : n_(n) { }
private:
int n_;
};
_START_GOOGLE_NAMESPACE_
template<> struct has_trivial_destructor<F> : true_type { };
_END_GOOGLE_NAMESPACE_
enum G {};
union H {};
class I {
public:
operator int() const;
};
class J {
private:
operator int() const;
};
namespace {
// A base class and a derived class that inherits from it, used for
// testing conversion type traits.
class Base {
public:
virtual ~Base() { }
};
class Derived : public Base {
};
TEST(TypeTraitsTest, TestIsInteger) {
// Verify that is_integral is true for all integer types.
EXPECT_TRUE(is_integral<bool>::value);
EXPECT_TRUE(is_integral<char>::value);
EXPECT_TRUE(is_integral<unsigned char>::value);
EXPECT_TRUE(is_integral<signed char>::value);
EXPECT_TRUE(is_integral<wchar_t>::value);
EXPECT_TRUE(is_integral<int>::value);
EXPECT_TRUE(is_integral<unsigned int>::value);
EXPECT_TRUE(is_integral<short>::value);
EXPECT_TRUE(is_integral<unsigned short>::value);
EXPECT_TRUE(is_integral<long>::value);
EXPECT_TRUE(is_integral<unsigned long>::value);
// Verify that is_integral is false for a few non-integer types.
EXPECT_FALSE(is_integral<void>::value);
EXPECT_FALSE(is_integral<float>::value);
EXPECT_FALSE(is_integral<string>::value);
EXPECT_FALSE(is_integral<int*>::value);
EXPECT_FALSE(is_integral<A>::value);
EXPECT_FALSE((is_integral<pair<int, int> >::value));
// Verify that cv-qualified integral types are still integral, and
// cv-qualified non-integral types are still non-integral.
EXPECT_TRUE(is_integral<const char>::value);
EXPECT_TRUE(is_integral<volatile bool>::value);
EXPECT_TRUE(is_integral<const volatile unsigned int>::value);
EXPECT_FALSE(is_integral<const float>::value);
EXPECT_FALSE(is_integral<int* volatile>::value);
EXPECT_FALSE(is_integral<const volatile string>::value);
}
TEST(TypeTraitsTest, TestIsFloating) {
// Verify that is_floating_point is true for all floating-point types.
EXPECT_TRUE(is_floating_point<float>::value);
EXPECT_TRUE(is_floating_point<double>::value);
EXPECT_TRUE(is_floating_point<long double>::value);
// Verify that is_floating_point is false for a few non-float types.
EXPECT_FALSE(is_floating_point<void>::value);
EXPECT_FALSE(is_floating_point<long>::value);
EXPECT_FALSE(is_floating_point<string>::value);
EXPECT_FALSE(is_floating_point<float*>::value);
EXPECT_FALSE(is_floating_point<A>::value);
EXPECT_FALSE((is_floating_point<pair<int, int> >::value));
// Verify that cv-qualified floating point types are still floating, and
// cv-qualified non-floating types are still non-floating.
EXPECT_TRUE(is_floating_point<const float>::value);
EXPECT_TRUE(is_floating_point<volatile double>::value);
EXPECT_TRUE(is_floating_point<const volatile long double>::value);
EXPECT_FALSE(is_floating_point<const int>::value);
EXPECT_FALSE(is_floating_point<volatile string>::value);
EXPECT_FALSE(is_floating_point<const volatile char>::value);
}
TEST(TypeTraitsTest, TestIsPointer) {
// Verify that is_pointer is true for some pointer types.
EXPECT_TRUE(is_pointer<int*>::value);
EXPECT_TRUE(is_pointer<void*>::value);
EXPECT_TRUE(is_pointer<string*>::value);
EXPECT_TRUE(is_pointer<const void*>::value);
EXPECT_TRUE(is_pointer<volatile float* const*>::value);
// Verify that is_pointer is false for some non-pointer types.
EXPECT_FALSE(is_pointer<void>::value);
EXPECT_FALSE(is_pointer<float&>::value);
EXPECT_FALSE(is_pointer<long>::value);
EXPECT_FALSE(is_pointer<vector<int*> >::value);
EXPECT_FALSE(is_pointer<int[5]>::value);
// A function pointer is a pointer, but a function type, or a function
// reference type, is not.
EXPECT_TRUE(is_pointer<int (*)(int x)>::value);
EXPECT_FALSE(is_pointer<void(char x)>::value);
EXPECT_FALSE(is_pointer<double (&)(string x)>::value);
// Verify that is_pointer<T> is true for some cv-qualified pointer types,
// and false for some cv-qualified non-pointer types.
EXPECT_TRUE(is_pointer<int* const>::value);
EXPECT_TRUE(is_pointer<const void* volatile>::value);
EXPECT_TRUE(is_pointer<char** const volatile>::value);
EXPECT_FALSE(is_pointer<const int>::value);
EXPECT_FALSE(is_pointer<volatile vector<int*> >::value);
EXPECT_FALSE(is_pointer<const volatile double>::value);
}
TEST(TypeTraitsTest, TestIsEnum) {
// is_enum isn't supported on MSVC or gcc 3.x
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
// Verify that is_enum is true for enum types.
EXPECT_TRUE(is_enum<G>::value);
EXPECT_TRUE(is_enum<const G>::value);
EXPECT_TRUE(is_enum<volatile G>::value);
EXPECT_TRUE(is_enum<const volatile G>::value);
// Verify that is_enum is false for a few non-enum types.
EXPECT_FALSE(is_enum<void>::value);
EXPECT_FALSE(is_enum<G&>::value);
EXPECT_FALSE(is_enum<G[1]>::value);
EXPECT_FALSE(is_enum<const G[1]>::value);
EXPECT_FALSE(is_enum<G[]>::value);
EXPECT_FALSE(is_enum<int>::value);
EXPECT_FALSE(is_enum<float>::value);
EXPECT_FALSE(is_enum<A>::value);
EXPECT_FALSE(is_enum<A*>::value);
EXPECT_FALSE(is_enum<const A>::value);
EXPECT_FALSE(is_enum<H>::value);
EXPECT_FALSE(is_enum<I>::value);
EXPECT_FALSE(is_enum<J>::value);
EXPECT_FALSE(is_enum<void()>::value);
EXPECT_FALSE(is_enum<void(*)()>::value);
EXPECT_FALSE(is_enum<int A::*>::value);
EXPECT_FALSE(is_enum<void (A::*)()>::value);
#endif
}
TEST(TypeTraitsTest, TestIsReference) {
// Verifies that is_reference is true for all reference types.
typedef float& RefFloat;
EXPECT_TRUE(is_reference<float&>::value);
EXPECT_TRUE(is_reference<const int&>::value);
EXPECT_TRUE(is_reference<const int*&>::value);
EXPECT_TRUE(is_reference<int (&)(bool)>::value);
EXPECT_TRUE(is_reference<RefFloat>::value);
EXPECT_TRUE(is_reference<const RefFloat>::value);
EXPECT_TRUE(is_reference<volatile RefFloat>::value);
EXPECT_TRUE(is_reference<const volatile RefFloat>::value);
// Verifies that is_reference is false for all non-reference types.
EXPECT_FALSE(is_reference<float>::value);
EXPECT_FALSE(is_reference<const float>::value);
EXPECT_FALSE(is_reference<volatile float>::value);
EXPECT_FALSE(is_reference<const volatile float>::value);
EXPECT_FALSE(is_reference<const int*>::value);
EXPECT_FALSE(is_reference<int()>::value);
EXPECT_FALSE(is_reference<void(*)(const char&)>::value);
}
TEST(TypeTraitsTest, TestAddReference) {
COMPILE_ASSERT_TYPES_EQ(int&, add_reference<int>::type);
COMPILE_ASSERT_TYPES_EQ(const int&, add_reference<const int>::type);
COMPILE_ASSERT_TYPES_EQ(volatile int&,
add_reference<volatile int>::type);
COMPILE_ASSERT_TYPES_EQ(const volatile int&,
add_reference<const volatile int>::type);
COMPILE_ASSERT_TYPES_EQ(int&, add_reference<int&>::type);
COMPILE_ASSERT_TYPES_EQ(const int&, add_reference<const int&>::type);
COMPILE_ASSERT_TYPES_EQ(volatile int&,
add_reference<volatile int&>::type);
COMPILE_ASSERT_TYPES_EQ(const volatile int&,
add_reference<const volatile int&>::type);
}
TEST(TypeTraitsTest, TestIsPod) {
// Verify that arithmetic types and pointers are marked as PODs.
EXPECT_TRUE(is_pod<bool>::value);
EXPECT_TRUE(is_pod<char>::value);
EXPECT_TRUE(is_pod<unsigned char>::value);
EXPECT_TRUE(is_pod<signed char>::value);
EXPECT_TRUE(is_pod<wchar_t>::value);
EXPECT_TRUE(is_pod<int>::value);
EXPECT_TRUE(is_pod<unsigned int>::value);
EXPECT_TRUE(is_pod<short>::value);
EXPECT_TRUE(is_pod<unsigned short>::value);
EXPECT_TRUE(is_pod<long>::value);
EXPECT_TRUE(is_pod<unsigned long>::value);
EXPECT_TRUE(is_pod<float>::value);
EXPECT_TRUE(is_pod<double>::value);
EXPECT_TRUE(is_pod<long double>::value);
EXPECT_TRUE(is_pod<string*>::value);
EXPECT_TRUE(is_pod<A*>::value);
EXPECT_TRUE(is_pod<const B*>::value);
EXPECT_TRUE(is_pod<C**>::value);
EXPECT_TRUE(is_pod<const int>::value);
EXPECT_TRUE(is_pod<char* volatile>::value);
EXPECT_TRUE(is_pod<const volatile double>::value);
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
EXPECT_TRUE(is_pod<G>::value);
EXPECT_TRUE(is_pod<const G>::value);
EXPECT_TRUE(is_pod<volatile G>::value);
EXPECT_TRUE(is_pod<const volatile G>::value);
#endif
// Verify that some non-POD types are not marked as PODs.
EXPECT_FALSE(is_pod<void>::value);
EXPECT_FALSE(is_pod<string>::value);
EXPECT_FALSE((is_pod<pair<int, int> >::value));
EXPECT_FALSE(is_pod<A>::value);
EXPECT_FALSE(is_pod<B>::value);
EXPECT_FALSE(is_pod<C>::value);
EXPECT_FALSE(is_pod<const string>::value);
EXPECT_FALSE(is_pod<volatile A>::value);
EXPECT_FALSE(is_pod<const volatile B>::value);
}
TEST(TypeTraitsTest, TestHasTrivialConstructor) {
// Verify that arithmetic types and pointers have trivial constructors.
EXPECT_TRUE(has_trivial_constructor<bool>::value);
EXPECT_TRUE(has_trivial_constructor<char>::value);
EXPECT_TRUE(has_trivial_constructor<unsigned char>::value);
EXPECT_TRUE(has_trivial_constructor<signed char>::value);
EXPECT_TRUE(has_trivial_constructor<wchar_t>::value);
EXPECT_TRUE(has_trivial_constructor<int>::value);
EXPECT_TRUE(has_trivial_constructor<unsigned int>::value);
EXPECT_TRUE(has_trivial_constructor<short>::value);
EXPECT_TRUE(has_trivial_constructor<unsigned short>::value);
EXPECT_TRUE(has_trivial_constructor<long>::value);
EXPECT_TRUE(has_trivial_constructor<unsigned long>::value);
EXPECT_TRUE(has_trivial_constructor<float>::value);
EXPECT_TRUE(has_trivial_constructor<double>::value);
EXPECT_TRUE(has_trivial_constructor<long double>::value);
EXPECT_TRUE(has_trivial_constructor<string*>::value);
EXPECT_TRUE(has_trivial_constructor<A*>::value);
EXPECT_TRUE(has_trivial_constructor<const B*>::value);
EXPECT_TRUE(has_trivial_constructor<C**>::value);
// Verify that pairs and arrays of such types have trivial
// constructors.
typedef int int10[10];
EXPECT_TRUE((has_trivial_constructor<pair<int, char*> >::value));
EXPECT_TRUE(has_trivial_constructor<int10>::value);
// Verify that pairs of types without trivial constructors
// are not marked as trivial.
EXPECT_FALSE((has_trivial_constructor<pair<int, string> >::value));
EXPECT_FALSE((has_trivial_constructor<pair<string, int> >::value));
// Verify that types without trivial constructors are
// correctly marked as such.
EXPECT_FALSE(has_trivial_constructor<string>::value);
EXPECT_FALSE(has_trivial_constructor<vector<int> >::value);
// Verify that E, which we have declared to have a trivial
// constructor, is correctly marked as such.
EXPECT_TRUE(has_trivial_constructor<E>::value);
}
TEST(TypeTraitsTest, TestHasTrivialCopy) {
// Verify that arithmetic types and pointers have trivial copy
// constructors.
EXPECT_TRUE(has_trivial_copy<bool>::value);
EXPECT_TRUE(has_trivial_copy<char>::value);
EXPECT_TRUE(has_trivial_copy<unsigned char>::value);
EXPECT_TRUE(has_trivial_copy<signed char>::value);
EXPECT_TRUE(has_trivial_copy<wchar_t>::value);
EXPECT_TRUE(has_trivial_copy<int>::value);
EXPECT_TRUE(has_trivial_copy<unsigned int>::value);
EXPECT_TRUE(has_trivial_copy<short>::value);
EXPECT_TRUE(has_trivial_copy<unsigned short>::value);
EXPECT_TRUE(has_trivial_copy<long>::value);
EXPECT_TRUE(has_trivial_copy<unsigned long>::value);
EXPECT_TRUE(has_trivial_copy<float>::value);
EXPECT_TRUE(has_trivial_copy<double>::value);
EXPECT_TRUE(has_trivial_copy<long double>::value);
EXPECT_TRUE(has_trivial_copy<string*>::value);
EXPECT_TRUE(has_trivial_copy<A*>::value);
EXPECT_TRUE(has_trivial_copy<const B*>::value);
EXPECT_TRUE(has_trivial_copy<C**>::value);
// Verify that pairs and arrays of such types have trivial
// copy constructors.
typedef int int10[10];
EXPECT_TRUE((has_trivial_copy<pair<int, char*> >::value));
EXPECT_TRUE(has_trivial_copy<int10>::value);
// Verify that pairs of types without trivial copy constructors
// are not marked as trivial.
EXPECT_FALSE((has_trivial_copy<pair<int, string> >::value));
EXPECT_FALSE((has_trivial_copy<pair<string, int> >::value));
// Verify that types without trivial copy constructors are
// correctly marked as such.
EXPECT_FALSE(has_trivial_copy<string>::value);
EXPECT_FALSE(has_trivial_copy<vector<int> >::value);
// Verify that C, which we have declared to have a trivial
// copy constructor, is correctly marked as such.
EXPECT_TRUE(has_trivial_copy<C>::value);
}
TEST(TypeTraitsTest, TestHasTrivialAssign) {
// Verify that arithmetic types and pointers have trivial assignment
// operators.
EXPECT_TRUE(has_trivial_assign<bool>::value);
EXPECT_TRUE(has_trivial_assign<char>::value);
EXPECT_TRUE(has_trivial_assign<unsigned char>::value);
EXPECT_TRUE(has_trivial_assign<signed char>::value);
EXPECT_TRUE(has_trivial_assign<wchar_t>::value);
EXPECT_TRUE(has_trivial_assign<int>::value);
EXPECT_TRUE(has_trivial_assign<unsigned int>::value);
EXPECT_TRUE(has_trivial_assign<short>::value);
EXPECT_TRUE(has_trivial_assign<unsigned short>::value);
EXPECT_TRUE(has_trivial_assign<long>::value);
EXPECT_TRUE(has_trivial_assign<unsigned long>::value);
EXPECT_TRUE(has_trivial_assign<float>::value);
EXPECT_TRUE(has_trivial_assign<double>::value);
EXPECT_TRUE(has_trivial_assign<long double>::value);
EXPECT_TRUE(has_trivial_assign<string*>::value);
EXPECT_TRUE(has_trivial_assign<A*>::value);
EXPECT_TRUE(has_trivial_assign<const B*>::value);
EXPECT_TRUE(has_trivial_assign<C**>::value);
// Verify that pairs and arrays of such types have trivial
// assignment operators.
typedef int int10[10];
EXPECT_TRUE((has_trivial_assign<pair<int, char*> >::value));
EXPECT_TRUE(has_trivial_assign<int10>::value);
// Verify that pairs of types without trivial assignment operators
// are not marked as trivial.
EXPECT_FALSE((has_trivial_assign<pair<int, string> >::value));
EXPECT_FALSE((has_trivial_assign<pair<string, int> >::value));
// Verify that types without trivial assignment operators are
// correctly marked as such.
EXPECT_FALSE(has_trivial_assign<string>::value);
EXPECT_FALSE(has_trivial_assign<vector<int> >::value);
// Verify that D, which we have declared to have a trivial
// assignment operator, is correctly marked as such.
EXPECT_TRUE(has_trivial_assign<D>::value);
}
TEST(TypeTraitsTest, TestHasTrivialDestructor) {
// Verify that arithmetic types and pointers have trivial destructors.
EXPECT_TRUE(has_trivial_destructor<bool>::value);
EXPECT_TRUE(has_trivial_destructor<char>::value);
EXPECT_TRUE(has_trivial_destructor<unsigned char>::value);
EXPECT_TRUE(has_trivial_destructor<signed char>::value);
EXPECT_TRUE(has_trivial_destructor<wchar_t>::value);
EXPECT_TRUE(has_trivial_destructor<int>::value);
EXPECT_TRUE(has_trivial_destructor<unsigned int>::value);
EXPECT_TRUE(has_trivial_destructor<short>::value);
EXPECT_TRUE(has_trivial_destructor<unsigned short>::value);
EXPECT_TRUE(has_trivial_destructor<long>::value);
EXPECT_TRUE(has_trivial_destructor<unsigned long>::value);
EXPECT_TRUE(has_trivial_destructor<float>::value);
EXPECT_TRUE(has_trivial_destructor<double>::value);
EXPECT_TRUE(has_trivial_destructor<long double>::value);
EXPECT_TRUE(has_trivial_destructor<string*>::value);
EXPECT_TRUE(has_trivial_destructor<A*>::value);
EXPECT_TRUE(has_trivial_destructor<const B*>::value);
EXPECT_TRUE(has_trivial_destructor<C**>::value);
// Verify that pairs and arrays of such types have trivial
// destructors.
typedef int int10[10];
EXPECT_TRUE((has_trivial_destructor<pair<int, char*> >::value));
EXPECT_TRUE(has_trivial_destructor<int10>::value);
// Verify that pairs of types without trivial destructors
// are not marked as trivial.
EXPECT_FALSE((has_trivial_destructor<pair<int, string> >::value));
EXPECT_FALSE((has_trivial_destructor<pair<string, int> >::value));
// Verify that types without trivial destructors are
// correctly marked as such.
EXPECT_FALSE(has_trivial_destructor<string>::value);
EXPECT_FALSE(has_trivial_destructor<vector<int> >::value);
// Verify that F, which we have declared to have a trivial
// destructor, is correctly marked as such.
EXPECT_TRUE(has_trivial_destructor<F>::value);
}
// Tests remove_pointer.
TEST(TypeTraitsTest, TestRemovePointer) {
COMPILE_ASSERT_TYPES_EQ(int, remove_pointer<int>::type);
COMPILE_ASSERT_TYPES_EQ(int, remove_pointer<int*>::type);
COMPILE_ASSERT_TYPES_EQ(const int, remove_pointer<const int*>::type);
COMPILE_ASSERT_TYPES_EQ(int, remove_pointer<int* const>::type);
COMPILE_ASSERT_TYPES_EQ(int, remove_pointer<int* volatile>::type);
}
TEST(TypeTraitsTest, TestRemoveConst) {
COMPILE_ASSERT_TYPES_EQ(int, remove_const<int>::type);
COMPILE_ASSERT_TYPES_EQ(int, remove_const<const int>::type);
COMPILE_ASSERT_TYPES_EQ(int *, remove_const<int * const>::type);
// TR1 examples.
COMPILE_ASSERT_TYPES_EQ(const int *, remove_const<const int *>::type);
COMPILE_ASSERT_TYPES_EQ(volatile int,
remove_const<const volatile int>::type);
}
TEST(TypeTraitsTest, TestRemoveVolatile) {
COMPILE_ASSERT_TYPES_EQ(int, remove_volatile<int>::type);
COMPILE_ASSERT_TYPES_EQ(int, remove_volatile<volatile int>::type);
COMPILE_ASSERT_TYPES_EQ(int *, remove_volatile<int * volatile>::type);
// TR1 examples.
COMPILE_ASSERT_TYPES_EQ(volatile int *,
remove_volatile<volatile int *>::type);
COMPILE_ASSERT_TYPES_EQ(const int,
remove_volatile<const volatile int>::type);
}
TEST(TypeTraitsTest, TestRemoveCV) {
COMPILE_ASSERT_TYPES_EQ(int, remove_cv<int>::type);
COMPILE_ASSERT_TYPES_EQ(int, remove_cv<volatile int>::type);
COMPILE_ASSERT_TYPES_EQ(int, remove_cv<const int>::type);
COMPILE_ASSERT_TYPES_EQ(int *, remove_cv<int * const volatile>::type);
// TR1 examples.
COMPILE_ASSERT_TYPES_EQ(const volatile int *,
remove_cv<const volatile int *>::type);
COMPILE_ASSERT_TYPES_EQ(int,
remove_cv<const volatile int>::type);
}
TEST(TypeTraitsTest, TestRemoveReference) {
COMPILE_ASSERT_TYPES_EQ(int, remove_reference<int>::type);
COMPILE_ASSERT_TYPES_EQ(int, remove_reference<int&>::type);
COMPILE_ASSERT_TYPES_EQ(const int, remove_reference<const int&>::type);
COMPILE_ASSERT_TYPES_EQ(int*, remove_reference<int * &>::type);
}
TEST(TypeTraitsTest, TestIsSame) {
EXPECT_TRUE((is_same<int32, int32>::value));
EXPECT_FALSE((is_same<int32, int64>::value));
EXPECT_FALSE((is_same<int64, int32>::value));
EXPECT_FALSE((is_same<int, const int>::value));
EXPECT_TRUE((is_same<void, void>::value));
EXPECT_FALSE((is_same<void, int>::value));
EXPECT_FALSE((is_same<int, void>::value));
EXPECT_TRUE((is_same<int*, int*>::value));
EXPECT_TRUE((is_same<void*, void*>::value));
EXPECT_FALSE((is_same<int*, void*>::value));
EXPECT_FALSE((is_same<void*, int*>::value));
EXPECT_FALSE((is_same<void*, const void*>::value));
EXPECT_FALSE((is_same<void*, void* const>::value));
EXPECT_TRUE((is_same<Base*, Base*>::value));
EXPECT_TRUE((is_same<Derived*, Derived*>::value));
EXPECT_FALSE((is_same<Base*, Derived*>::value));
EXPECT_FALSE((is_same<Derived*, Base*>::value));
}
TEST(TypeTraitsTest, TestConvertible) {
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
EXPECT_TRUE((is_convertible<int, int>::value));
EXPECT_TRUE((is_convertible<int, long>::value));
EXPECT_TRUE((is_convertible<long, int>::value));
EXPECT_TRUE((is_convertible<int*, void*>::value));
EXPECT_FALSE((is_convertible<void*, int*>::value));
EXPECT_TRUE((is_convertible<Derived*, Base*>::value));
EXPECT_FALSE((is_convertible<Base*, Derived*>::value));
EXPECT_TRUE((is_convertible<Derived*, const Base*>::value));
EXPECT_FALSE((is_convertible<const Derived*, Base*>::value));
#endif
}
} // namespace
#include <iostream>
int main(int, char **) {
// All the work is done in the static constructors. If they don't
// die, the tests have all passed.
std::cout << "PASS\n";
return 0;
}

View file

@ -0,0 +1,173 @@
#ifndef GOOGLE_SPARSEHASH_WINDOWS_CONFIG_H_
#define GOOGLE_SPARSEHASH_WINDOWS_CONFIG_H_
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Namespace for Google classes */
#define GOOGLE_NAMESPACE ::google
#if (_MSC_VER >= 1800 )
/* the location of the header defining hash functions */
#define HASH_FUN_H <unordered_map>
/* the location of <unordered_map> or <hash_map> */
#define HASH_MAP_H <unordered_map>
/* the location of <unordered_set> or <hash_set> */
#define HASH_SET_H <unordered_set>
/* define if the compiler has hash_map */
#define HAVE_HASH_MAP 0
/* define if the compiler has hash_set */
#define HAVE_HASH_SET 0
/* define if the compiler supports unordered_{map,set} */
#define HAVE_UNORDERED_MAP 1
#else /* Earlier than VSC++ 2013 */
/* the location of the header defining hash functions */
#define HASH_FUN_H <hash_map>
/* the location of <unordered_map> or <hash_map> */
#define HASH_MAP_H <hash_map>
/* the location of <unordered_set> or <hash_set> */
#define HASH_SET_H <hash_set>
/* define if the compiler has hash_map */
#define HAVE_HASH_MAP 1
/* define if the compiler has hash_set */
#define HAVE_HASH_SET 1
/* define if the compiler supports unordered_{map,set} */
#undef HAVE_UNORDERED_MAP
#endif
/* the namespace of the hash<> function */
#define HASH_NAMESPACE stdext
/* Define to 1 if you have the <google/malloc_extension.h> header file. */
#undef HAVE_GOOGLE_MALLOC_EXTENSION_H
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if the system has the type `long long'. */
#define HAVE_LONG_LONG 1
/* Define to 1 if you have the `memcpy' function. */
#define HAVE_MEMCPY 1
/* Define to 1 if you have the `memmove' function. */
#define HAVE_MEMMOVE 1
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* define if the compiler implements namespaces */
#define HAVE_NAMESPACES 1
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/utsname.h> header file. */
#undef HAVE_SYS_UTSNAME_H
/* Define to 1 if the system has the type `uint16_t'. */
#undef HAVE_UINT16_T
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if the system has the type `u_int16_t'. */
#undef HAVE_U_INT16_T
/* Define to 1 if the system has the type `__uint16'. */
#define HAVE___UINT16 1
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
/* The system-provided hash function including the namespace. */
#define SPARSEHASH_HASH HASH_NAMESPACE::hash_compare
/* The system-provided hash function, in namespace HASH_NAMESPACE. */
#define SPARSEHASH_HASH_NO_NAMESPACE hash_compare
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#undef VERSION
/* Stops putting the code inside the Google namespace */
#define _END_GOOGLE_NAMESPACE_ }
/* Puts following code inside the Google namespace */
#define _START_GOOGLE_NAMESPACE_ namespace google {
// ---------------------------------------------------------------------
// Extra stuff not found in config.h.in
#define HAVE_WINDOWS_H 1 // used in time_hash_map
// This makes sure the definitions in config.h and sparseconfig.h match
// up. If they don't, the compiler will complain about redefinition.
#include <sparsehash/internal/sparseconfig.h>
// TODO(csilvers): include windows/port.h in every relevant source file instead?
#include "windows/port.h"
#endif /* GOOGLE_SPARSEHASH_WINDOWS_CONFIG_H_ */

View file

@ -0,0 +1,49 @@
/*
* NOTE: This file is for internal use only.
* Do not use these #defines in your own program!
*/
/* Namespace for Google classes */
#define GOOGLE_NAMESPACE ::google
/* the location of the header defining hash functions */
#define HASH_FUN_H <hash_map>
/* the namespace of the hash<> function */
#define HASH_NAMESPACE stdext
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if the system has the type `long long'. */
#define HAVE_LONG_LONG 1
/* Define to 1 if you have the `memcpy' function. */
#define HAVE_MEMCPY 1
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if the system has the type `uint16_t'. */
#undef HAVE_UINT16_T
/* Define to 1 if the system has the type `u_int16_t'. */
#undef HAVE_U_INT16_T
/* Define to 1 if the system has the type `__uint16'. */
#define HAVE___UINT16 1
/* The system-provided hash function including the namespace. */
#define SPARSEHASH_HASH HASH_NAMESPACE::hash_compare
/* The system-provided hash function, in namespace HASH_NAMESPACE. */
#define SPARSEHASH_HASH_NO_NAMESPACE hash_compare
/* Stops putting the code inside the Google namespace */
#define _END_GOOGLE_NAMESPACE_ }
/* Puts following code inside the Google namespace */
#define _START_GOOGLE_NAMESPACE_ namespace google {

View file

@ -0,0 +1,64 @@
/* Copyright (c) 2007, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ---
* Author: Craig Silverstein
*/
#include <sparsehash/internal/sparseconfig.h>
#ifndef WIN32
# error You should only be including windows/port.cc in a windows environment!
#endif
#include "config.h"
#include <stdarg.h> // for va_list, va_start, va_end
#include "port.h"
// Calls the windows _vsnprintf, but always NUL-terminate.
int snprintf(char *str, size_t size, const char *format, ...) {
if (size == 0) // not even room for a \0?
return -1; // not what C99 says to do, but what windows does
str[size-1] = '\0';
va_list ap;
va_start(ap, format);
const int r = _vsnprintf(str, size-1, format, ap);
va_end(ap);
return r;
}
std::string TmpFile(const char* basename) {
char tmppath_buffer[1024];
int tmppath_len = GetTempPathA(sizeof(tmppath_buffer), tmppath_buffer);
if (tmppath_len <= 0 || tmppath_len >= sizeof(tmppath_buffer)) {
return basename; // an error, so just bail on tmppath
}
snprintf(tmppath_buffer + tmppath_len, sizeof(tmppath_buffer) - tmppath_len,
"\\%s", basename);
return tmppath_buffer;
}

View file

@ -0,0 +1,72 @@
/* Copyright (c) 2007, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ---
* Author: Craig Silverstein
*
* These are some portability typedefs and defines to make it a bit
* easier to compile this code -- in particular, unittests -- under VC++.
* Other portability code is found in windows/sparsehash/internal/sparseconfig.h.
*
* Several of these are taken from glib:
* http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html
*/
#ifndef SPARSEHASH_WINDOWS_PORT_H_
#define SPARSEHASH_WINDOWS_PORT_H_
#include <sparsehash/internal/sparseconfig.h>
#include "config.h"
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */
#include <windows.h>
#include <io.h> /* because we so often use open/close/etc */
#include <string>
// 4996: Yes, we're ok using the "unsafe" functions like _vsnprintf and fopen
// 4127: We use "while (1)" sometimes: yes, we know it's a constant
// 4181: type_traits_test is explicitly testing 'qualifier applied to reference'
#pragma warning(disable:4996 4127 4181)
// file I/O
#define unlink _unlink
#define strdup _strdup
// We can't just use _snprintf as a drop-in replacement, because it
// doesn't always NUL-terminate. :-(
extern int snprintf(char *str, size_t size, const char *format, ...);
extern std::string TmpFile(const char* basename); // used in hashtable_unittest
#endif /* WIN32 */
#endif /* SPARSEHASH_WINDOWS_PORT_H_ */

View file

@ -0,0 +1,58 @@
/*
* NOTE: This file is for internal use only.
* Do not use these #defines in your own program!
*/
/* Namespace for Google classes */
#define GOOGLE_NAMESPACE ::google
#if (_MSC_VER >= 1800 )
/* the location of the header defining hash functions */
#define HASH_FUN_H <unordered_map>
#else /* Earlier than VSC++ 2013 */
/* the location of the header defining hash functions */
#define HASH_FUN_H <hash_map>
#endif
/* the namespace of the hash<> function */
#define HASH_NAMESPACE stdext
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if the system has the type `long long'. */
#define HAVE_LONG_LONG 1
/* Define to 1 if you have the `memcpy' function. */
#define HAVE_MEMCPY 1
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if the system has the type `uint16_t'. */
#undef HAVE_UINT16_T
/* Define to 1 if the system has the type `u_int16_t'. */
#undef HAVE_U_INT16_T
/* Define to 1 if the system has the type `__uint16'. */
#define HAVE___UINT16 1
/* The system-provided hash function including the namespace. */
#define SPARSEHASH_HASH HASH_NAMESPACE::hash_compare
/* The system-provided hash function, in namespace HASH_NAMESPACE. */
#define SPARSEHASH_HASH_NO_NAMESPACE hash_compare
/* Stops putting the code inside the Google namespace */
#define _END_GOOGLE_NAMESPACE_ }
/* Puts following code inside the Google namespace */
#define _START_GOOGLE_NAMESPACE_ namespace google {